{"action":"created","issue":{"url":"https://api.github.com/repos/pleriche/FastMM4/issues/54","repository_url":"https://api.github.com/repos/pleriche/FastMM4","labels_url":"https://api.github.com/repos/pleriche/FastMM4/issues/54/labels{/name}","comments_url":"https://api.github.com/repos/pleriche/FastMM4/issues/54/comments","events_url":"https://api.github.com/repos/pleriche/FastMM4/issues/54/events","html_url":"https://github.com/pleriche/FastMM4/issues/54","id":320215076,"number":54,"title":"Pooling large blocks","user":{"login":"obones","id":1314739,"avatar_url":"https://avatars0.githubusercontent.com/u/1314739?v=4","gravatar_id":"","url":"https://api.github.com/users/obones","html_url":"https://github.com/obones","followers_url":"https://api.github.com/users/obones/followers","following_url":"https://api.github.com/users/obones/following{/other_user}","gists_url":"https://api.github.com/users/obones/gists{/gist_id}","starred_url":"https://api.github.com/users/obones/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/obones/subscriptions","organizations_url":"https://api.github.com/users/obones/orgs","repos_url":"https://api.github.com/users/obones/repos","events_url":"https://api.github.com/users/obones/events{/privacy}","received_events_url":"https://api.github.com/users/obones/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":4,"created_at":"2018-05-04T09:52:32Z","updated_at":"2018-05-04T13:14:00Z","closed_at":null,"author_association":"NONE","body":"We are using FastMM in its latest version in our application and are very pleased with its capabilities, especially the full debug mode support.\r\nHowever, in memory intensive cases, its performances are really below what we can achieve with TBBMalloc, but this one has serious disadvantages of its own on machines with lots of cores (>16)\r\nDigging in our own source code, we came up with a simple example that illustrates the issue, which code is as follows:\r\n\r\n```\r\nprogram TestFastMM;\r\n\r\n{$APPTYPE CONSOLE}\r\n\r\n{$R *.res}\r\n\r\nuses\r\n  FastMM4,\r\n  System.Diagnostics,\r\n  System.TimeSpan,\r\n  System.SysUtils,\r\n  System.Classes,\r\n  System.Generics.Collections,\r\n  Winapi.Windows;\r\n\r\ntype\r\n  TTestThread = class(TThread)\r\n  public\r\n  procedure Execute; override;\r\n  end;\r\n\r\nvar\r\n  Stopwatch: TStopwatch;\r\n  Elapsed: TTimeSpan;\r\n  ThreadList: TList<TThread>;\r\n  Threads: array of TTestThread;\r\n  iGlobal: Integer;\r\n\r\nconst\r\n  C_StrL = 16351;\r\n{ TTestThread }\r\n\r\nprocedure TTestThread.Execute;\r\nvar\r\n  CurrentStringList: TStringList;\r\n  i: Integer;\r\n  CurrentString: string;\r\nbegin\r\n  CurrentStringList := TStringList.Create;\r\n  try\r\n    for I := 1 to 1571000 do\r\n    begin\r\n      SetLength(CurrentString, C_StrL);\r\n      SetLength(CurrentString, 0);\r\n      CurrentStringList.Add(IntToStr(Random(i)) + 'bob' + IntToStr(Random(i)));\r\n    end;\r\n  finally\r\n    CurrentStringList.Free;\r\n  end;\r\nend;\r\n\r\nbegin\r\n  try\r\n    Stopwatch := TStopwatch.StartNew;\r\n\r\n    SetLength(Threads, 40); // highly parallel\r\n    ThreadList := TList<TThread>.Create;\r\n    try\r\n      for iGlobal := Low(Threads) to High(Threads) do\r\n      begin\r\n        Threads[iGlobal] := TTestThread.Create;\r\n        ThreadList.Add(Threads[iGlobal]);\r\n      end;\r\n\r\n      while ThreadList.Count > 0 do\r\n      begin\r\n        if ThreadList[0].WaitFor = WAIT_OBJECT_0 then\r\n          ThreadList.Delete(0);\r\n        Sleep(10);\r\n      end;\r\n    finally\r\n      ThreadList.Free;\r\n    end;\r\n\r\n    Elapsed := Stopwatch.Elapsed;\r\n    Writeln(Format('FastMM took %n milliseconds', [Elapsed.TotalMilliseconds]));\r\n  except\r\n    on E: Exception do\r\n      Writeln(E.ClassName, ': ', E.Message);\r\n  end;\r\n  ReadLn;\r\nend.\r\n```\r\n\r\nOn my Core i7 computer, this takes around 25s while the same program with TBBMalloc takes only 5.\r\nLooking at FastMM source code, I discovered that this is because our `TStringList ` quickly grows above the maximum medium block size which is 264768 bytes and thus leads to lots of calls to `VirtualAlloc` inside `AllocateLargeBlock`. In the program above, there are 448 calls, which, if this is the only difference, accounts for 40ms per call to `VirtualAlloc` (that sounds quite realistic).\r\nI tried adjusting `MediumBlockBinGroupCount` so that I get a larger value for `MaximumMediumBlockSize` but all I achieved was to get Access violations very fast.\r\n\r\nIn the end, I believe it would be much nicer if the large blocks were also pooled like small and large blocks, which would be very nice for us as we are manipulating lots of objects in lists under our x64 applications.\r\n\r\nWould anyone have any suggestion on this subject?"},"comment":{"url":"https://api.github.com/repos/pleriche/FastMM4/issues/comments/386597384","html_url":"https://github.com/pleriche/FastMM4/issues/54#issuecomment-386597384","issue_url":"https://api.github.com/repos/pleriche/FastMM4/issues/54","id":386597384,"user":{"login":"petr-nehez","id":1265990,"avatar_url":"https://avatars3.githubusercontent.com/u/1265990?v=4","gravatar_id":"","url":"https://api.github.com/users/petr-nehez","html_url":"https://github.com/petr-nehez","followers_url":"https://api.github.com/users/petr-nehez/followers","following_url":"https://api.github.com/users/petr-nehez/following{/other_user}","gists_url":"https://api.github.com/users/petr-nehez/gists{/gist_id}","starred_url":"https://api.github.com/users/petr-nehez/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/petr-nehez/subscriptions","organizations_url":"https://api.github.com/users/petr-nehez/orgs","repos_url":"https://api.github.com/users/petr-nehez/repos","events_url":"https://api.github.com/users/petr-nehez/events{/privacy}","received_events_url":"https://api.github.com/users/petr-nehez/received_events","type":"User","site_admin":false},"created_at":"2018-05-04T13:14:00Z","updated_at":"2018-05-04T13:14:00Z","author_association":"NONE","body":"That's interesting, we do have high contention so what I remember our module with FastMM was spending too much time in routines with `Sleep` and/or `SwitchToThread` calls.\r\n\r\nIt definitely depends on type of work the program does.\r\nYour program allocates large blocks whereas our does allocate large amount of small blocks."}}
{"actor":{"display_login":"petr-nehez"}}