diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bdebfa2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,59 @@ +.directory + +# Uncomment these types if you want even more clean repository. But be careful. +# It can make harm to an existing project source. Read explanations below. +# +# Resource files are binaries containing manifest, project icon and version info. +# They can not be viewed as text or compared by diff-tools. Consider replacing them with .rc files. +#*.res +# +# Type library file (binary). In old Delphi versions it should be stored. +# Since Delphi 2009 it is produced from .ridl file and can safely be ignored. +#*.tlb +# +# Diagram Portfolio file. Used by the diagram editor up to Delphi 7. +# Uncomment this if you are not using diagrams or use newer Delphi version. +#*.ddp +# +# Visual LiveBindings file. Added in Delphi XE2. +# Uncomment this if you are not using LiveBindings Designer. +#*.vlb +# +# Deployment Manager configuration file for your project. Added in Delphi XE2. +# Uncomment this if it is not mobile development and you do not use remote debug feature. +#*.deployproj +# + +# Delphi compiler-generated binaries (safe to delete) +*.exe +*.dll +*.bpl +*.bpi +*.dcp +*.so +*.apk +*.drc +*.map +*.dres +*.rsm +*.tds +*.dcu +*.lib + +# Delphi autogenerated files (duplicated info) +*.cfg +*Resource.rc + +# Delphi local files (user-specific info) +*.local +*.identcache +*.projdata +*.tvsconfig +*.dsk + +# Delphi history and backups +__history/ +*.~* + +# Castalia statistics file +*.stat diff --git a/RegExpr/RegExpr.dcu b/RegExpr/RegExpr.dcu index d703b89..5049365 100644 Binary files a/RegExpr/RegExpr.dcu and b/RegExpr/RegExpr.dcu differ diff --git a/WinCacheGrind.dof b/WinCacheGrind.dof new file mode 100644 index 0000000..849dc40 --- /dev/null +++ b/WinCacheGrind.dof @@ -0,0 +1,136 @@ +[FileVersion] +Version=7.0 +[Compiler] +A=8 +B=0 +C=1 +D=1 +E=0 +F=0 +G=1 +H=1 +I=1 +J=0 +K=0 +L=1 +M=0 +N=1 +O=1 +P=1 +Q=0 +R=0 +S=0 +T=0 +U=0 +V=1 +W=0 +X=1 +Y=1 +Z=1 +ShowHints=1 +ShowWarnings=1 +UnitAliases=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; +NamespacePrefix= +SymbolDeprecated=1 +SymbolLibrary=1 +SymbolPlatform=1 +UnitLibrary=1 +UnitPlatform=1 +UnitDeprecated=1 +HResultCompat=1 +HidingMember=1 +HiddenVirtual=1 +Garbage=1 +BoundsError=1 +ZeroNilCompat=1 +StringConstTruncated=1 +ForLoopVarVarPar=1 +TypedConstVarPar=1 +AsgToTypedConst=1 +CaseLabelRange=1 +ForVariable=1 +ConstructingAbstract=1 +ComparisonFalse=1 +ComparisonTrue=1 +ComparingSignedUnsigned=1 +CombiningSignedUnsigned=1 +UnsupportedConstruct=1 +FileOpen=1 +FileOpenUnitSrc=1 +BadGlobalSymbol=1 +DuplicateConstructorDestructor=1 +InvalidDirective=1 +PackageNoLink=1 +PackageThreadVar=1 +ImplicitImport=1 +HPPEMITIgnored=1 +NoRetVal=1 +UseBeforeDef=1 +ForLoopVarUndef=1 +UnitNameMismatch=1 +NoCFGFileFound=1 +MessageDirective=1 +ImplicitVariants=1 +UnicodeToLocale=1 +LocaleToUnicode=1 +ImagebaseMultiple=1 +SuspiciousTypecast=1 +PrivatePropAccessor=1 +UnsafeType=0 +UnsafeCode=0 +UnsafeCast=0 +[Linker] +MapFile=0 +OutputObjs=0 +ConsoleApp=1 +DebugInfo=0 +RemoteSymbols=0 +MinStackSize=16384 +MaxStackSize=1048576 +ImageBase=4194304 +ExeDescription= +[Directories] +OutputDir= +UnitOutputDir= +PackageDLLOutputDir= +PackageDCPOutputDir= +SearchPath= +Packages= +Conditionals= +DebugSourceDirs= +UsePackages=0 +[Parameters] +RunParams= +HostApplication= +Launcher= +UseLauncher=0 +DebugCWD= +[Language] +ActiveLang= +ProjectLang= +RootDir= +[Version Info] +IncludeVerInfo=0 +AutoIncBuild=0 +MajorVer=1 +MinorVer=0 +Release=0 +Build=0 +Debug=0 +PreRelease=0 +Special=0 +Private=0 +DLL=0 +Locale=1057 +CodePage=1252 +[Version Info Keys] +CompanyName= +FileDescription= +FileVersion=1.0.0.0 +InternalName= +LegalCopyright= +LegalTrademarks= +OriginalFilename= +ProductName= +ProductVersion=1.0.0.0 +Comments= diff --git a/WinCacheGrind.ini b/WinCacheGrind.ini new file mode 100644 index 0000000..af59476 --- /dev/null +++ b/WinCacheGrind.ini @@ -0,0 +1,18 @@ +[Main] +WorkingDir= +[Display] +TimeDisplay=0 +HideFastFuncs=0 +FastThreshold=1 +HideLibFuncs=0 +ShowFullPath=0 +[Privacy] +TrackMRU=1 +ClearMRUOnExit=0 +MaxMRUCount=4 +[Editor] +EditorPath= +[MRU] +Count=1 +Entry0=C:\Users\ceefour\git\wincachegrind\test\cachegrind.out.test1compressed +Title0=/home/data/www/htdocs/example.php diff --git a/cachegrind.out File Format.md b/cachegrind.out File Format.md index 61ddf0b..33ed655 100644 --- a/cachegrind.out File Format.md +++ b/cachegrind.out File Format.md @@ -73,3 +73,11 @@ Why it's not included in "main program" is because these are called not by main program but by PHP mechanism. The entries here are identical to *BODY PART*. + +## File and Function Name Compresssion + +See http://valgrind.org/docs/manual/cl-format.html#cl-format.overview.compression1 + +Original issue: https://github.com/ceefour/wincachegrind/issues/1 + +Thanks to Stéphane Boisvert for donation. :) diff --git a/test/cachegrind.out._mnt_hgfs_www_www_www_test_php b/test/cachegrind.out._mnt_hgfs_www_www_www_test_php new file mode 100644 index 0000000..ac4bd12 --- /dev/null +++ b/test/cachegrind.out._mnt_hgfs_www_www_www_test_php @@ -0,0 +1,183 @@ +version: 1 +creator: xdebug 2.3.2 +cmd: E:/www/www/www/test.php +part: 1 +positions: line + +events: Time + +fl=(1) E:/www/www/www/test.php +fn=(1) B->_sayEnd +12 3 + +fl=(1) +fn=(2) A->say +3 54 +cfl=(1) +cfn=(1) +calls=1 0 0 +6 3 + +fl=(1) +fn=(1) +12 0 + +fl=(1) +fn=(2) +3 24 +cfl=(1) +cfn=(1) +calls=1 0 0 +6 0 + +fl=(1) +fn=(1) +12 0 + +fl=(1) +fn=(2) +3 22 +cfl=(1) +cfn=(1) +calls=1 0 0 +6 0 + +fl=(1) +fn=(1) +12 0 + +fl=(1) +fn=(2) +3 20 +cfl=(1) +cfn=(1) +calls=1 0 0 +6 0 + +fl=(1) +fn=(1) +12 1 + +fl=(1) +fn=(2) +3 21 +cfl=(1) +cfn=(1) +calls=1 0 0 +6 1 + +fl=(1) +fn=(1) +12 1 + +fl=(1) +fn=(2) +3 20 +cfl=(1) +cfn=(1) +calls=1 0 0 +6 1 + +fl=(1) +fn=(1) +12 0 + +fl=(1) +fn=(2) +3 46 +cfl=(1) +cfn=(1) +calls=1 0 0 +6 0 + +fl=(1) +fn=(1) +12 0 + +fl=(1) +fn=(2) +3 22 +cfl=(1) +cfn=(1) +calls=1 0 0 +6 0 + +fl=(1) +fn=(1) +12 0 + +fl=(1) +fn=(2) +3 20 +cfl=(1) +cfn=(1) +calls=1 0 0 +6 0 + +fl=(1) +fn=(1) +12 0 + +fl=(1) +fn=(2) +3 20 +cfl=(1) +cfn=(1) +calls=1 0 0 +6 0 + +fl=(1) +fn=(3) thisIsFun +17 309 +cfl=(1) +cfn=(2) +calls=1 0 0 +20 57 +cfl=(1) +cfn=(2) +calls=1 0 0 +20 25 +cfl=(1) +cfn=(2) +calls=1 0 0 +20 23 +cfl=(1) +cfn=(2) +calls=1 0 0 +20 21 +cfl=(1) +cfn=(2) +calls=1 0 0 +20 22 +cfl=(1) +cfn=(2) +calls=1 0 0 +20 22 +cfl=(1) +cfn=(2) +calls=1 0 0 +20 47 +cfl=(1) +cfn=(2) +calls=1 0 0 +20 23 +cfl=(1) +cfn=(2) +calls=1 0 0 +20 21 +cfl=(1) +cfn=(2) +calls=1 0 0 +20 21 + +fl=(1) +fn=(4) {main} + +summary: 708 + +1 108 +cfl=(1) +cfn=(3) +calls=1 0 0 +23 600 + diff --git a/test/cachegrind.out.bug00631 b/test/cachegrind.out.bug00631 new file mode 100644 index 0000000..f47c1f8 --- /dev/null +++ b/test/cachegrind.out.bug00631 @@ -0,0 +1,34 @@ +version: 1 +creator: xdebug 3.%s +cmd: %sbug00631.php +part: 1 +positions: line + +events: Time + +fl=(1) php:internal +fn=(1) php::register_shutdown_function +%d %d + +fl=(1) +fn=(2) php::strlen +%d %d + +fl=(2) %sbug00631.php +fn=(3) {main} + +summary: %d + +%d %d +cfl=(1) +cfn=(1) +calls=1 0 0 +%d %d +cfl=(1) +cfn=(2) +calls=1 0 0 +%d %d + +fl=(1) +fn=(4) php::xdebug_get_profiler_filename +%d %d diff --git a/test/cachegrind.out.test1 b/test/cachegrind.out.test1 new file mode 100644 index 0000000..1c3b145 --- /dev/null +++ b/test/cachegrind.out.test1 @@ -0,0 +1,34 @@ +version: 0.9.6 +cmd: /home/data/www/htdocs/example.php +part: 1 + +events: Time Memory Cycles Peakmemory + +fl=/home/data/www/htdocs/example.php +fn=test3 +11 16 40 0 0 + +fl=/home/data/www/htdocs/example.php +fn=test3 +12 7 0 0 0 + +fl=/home/data/www/htdocs/example.php +fn=test2 +7 141 120 0 0 +cfn=test3 +calls=1 0 0 +11 16 40 0 0 +cfn=test3 +calls=1 0 0 +12 7 0 0 0 + +fl=/home/data/www/htdocs/example.php +fn=test1 +3 60 120 0 0 +cfn=test2 +calls=1 0 0 +7 165 160 0 0 + +fl=/home/data/www/htdocs/example.php +fn=test4 +4 6 0 0 0 diff --git a/test/cachegrind.out.test1compressed b/test/cachegrind.out.test1compressed new file mode 100644 index 0000000..d9e54e0 --- /dev/null +++ b/test/cachegrind.out.test1compressed @@ -0,0 +1,34 @@ +version: 0.9.6 +cmd: /home/data/www/htdocs/example.php +part: 1 + +events: Time Memory Cycles Peakmemory + +fl=(1) /home/data/www/htdocs/example.php +fn=(1) test3 +11 16 40 0 0 + +fl=(1) +fn=(1) +12 7 0 0 0 + +fl=(1) +fn=(2) test2 +7 141 120 0 0 +cfn=(1) +calls=1 0 0 +11 16 40 0 0 +cfn=(1) +calls=1 0 0 +12 7 0 0 0 + +fl=(1) +fn=test1 +3 60 120 0 0 +cfn=(2) +calls=1 0 0 +7 165 160 0 0 + +fl=(1) +fn=test4 +4 6 0 0 0 diff --git a/uCacheGrind.pas b/uCacheGrind.pas index ed6753b..d2c1b01 100644 --- a/uCacheGrind.pas +++ b/uCacheGrind.pas @@ -19,7 +19,7 @@ interface -uses Classes, SysUtils, JclStrHashMap; +uses Classes, SysUtils, JclStrHashMap, RegExpr; type // Types @@ -697,6 +697,37 @@ TCallBuffer = record CurInst, LastInst: TProfInstance; Stack, Buffer: TList; I, P, ParserLine: Integer; + Compresseds: TStringHashMap; + +function Uncompress(section: string; raw: string): string; +var + id: string; + key: string; + _content: PString; +begin + with TRegExpr.Create do try + // check if this is an assignment of compression + Expression := '\((\d+)\)\s*(.*)'; + if Exec(raw) then begin + id := Match[1]; + key := section + '-' + id; + if Match[2] <> '' then begin + // this is an assignment + New(_content); + _content^ := Match[2]; + Compresseds.Add(key, _content); + Result := Match[2]; + end else begin + // this is an uncompression + Result := PString(Compresseds.Data[key])^; + end; + end else begin + // otherwise just return as-is + Result := raw; + end; + finally Free; + end; +end; procedure Error(Msg: string); var @@ -752,6 +783,12 @@ procedure ClearBuffer; Buffer.Clear; end; + function FreeHashData(AUserData: Pointer; AStr: string; var APtr: PString): Boolean; + begin + Dispose(APtr); + Result := True; + end; + var CurBuf: PCallBuffer; Target: TProfInstance; @@ -777,6 +814,7 @@ procedure ClearBuffer; FSummaryExists := False; Stack := TList.Create; Buffer := TList.Create; + Compresseds := TStringHashMap.Create(TCaseSensitiveTraits.Create, 100000); ParserLine := 1; try while not Eof(F) do begin @@ -799,10 +837,10 @@ procedure ClearBuffer; State := stBody; end; stBody: begin - if Copy(S, 1, 3) = 'fl=' then - CurFL := Copy(S, 3 + 1, Length(S) - 3) - else if Copy(S, 1, 3) = 'fn=' then begin - CurFN := Copy(S, 3 + 1, Length(S) - 3); + if Copy(S, 1, 3) = 'fl=' then begin + CurFL := Uncompress('fl', Copy(S, 3 + 1, Length(S) - 3) ) + end else if Copy(S, 1, 3) = 'fn=' then begin + CurFN := Uncompress('fn', Copy(S, 3 + 1, Length(S) - 3) ); if CurFL = '' then Error('Parser error: fl is not valid.'); if CurFN = '' then Error('Parser error: fn is not valid.'); CurInst := CreateInstance(CurFN, CurFL); // TODO: SLOW! @@ -831,7 +869,7 @@ procedure ClearBuffer; // must have inst first if CurInst = nil then Error('Parser error: Parsing '+ S +': Current instance is NULL.'); // get function name - A := Copy(S, 4 + 1, Length(S) - 4); + A := Uncompress('fn', Copy(S, 4 + 1, Length(S) - 4) ); // add to call buffer New(CurBuf); Buffer.Add(CurBuf); @@ -925,6 +963,8 @@ procedure ClearBuffer; Stack.Clear; end; finally + Compresseds.Iterate(nil, @FreeHashData); + Compresseds.Free; Stack.Free; Buffer.Free; end; diff --git a/uMain.ddp b/uMain.ddp new file mode 100644 index 0000000..4370276 Binary files /dev/null and b/uMain.ddp differ diff --git a/uMain.dfm b/uMain.dfm index 32bb452..5ecd353 100644 --- a/uMain.dfm +++ b/uMain.dfm @@ -1,6 +1,6 @@ object fMain: TfMain - Left = 855 - Top = 272 + Left = 637 + Top = 224 Width = 635 Height = 431 ActiveControl = lvExplorer @@ -24,16 +24,16 @@ object fMain: TfMain TextHeight = 13 object sExplorer: TSplitter Left = 0 - Top = 270 - Width = 627 + Top = 257 + Width = 619 Height = 4 Cursor = crVSplit Align = alBottom end object sb: TStatusBar Left = 0 - Top = 366 - Width = 627 + Top = 353 + Width = 619 Height = 19 AutoHint = True Panels = < @@ -45,7 +45,7 @@ object fMain: TfMain object ToolBar1: TToolBar Left = 0 Top = 0 - Width = 627 + Width = 619 Height = 28 AutoSize = True BorderWidth = 1 @@ -112,8 +112,8 @@ object fMain: TfMain end object lvExplorer: TListView Left = 0 - Top = 274 - Width = 627 + Top = 261 + Width = 619 Height = 92 Align = alBottom Columns = < @@ -151,7 +151,7 @@ object fMain: TfMain object tbTabs: TJvTabBar Left = 0 Top = 28 - Width = 627 + Width = 619 Images = ilIcons Tabs = < item diff --git a/uMain.pas b/uMain.pas index 4a4bc66..993e313 100644 --- a/uMain.pas +++ b/uMain.pas @@ -305,15 +305,14 @@ procedure TfMain.aHelpAboutExecute(Sender: TObject); try MessageDlg( 'WinCacheGrind version '+ VI.BinFileVersion + #13#10 + - 'Copyright (C) 2005 Hendy Irawan'#13#10 + + 'Copyright (C) 2005-2015 Hendy Irawan'#13#10 + #13#10 + 'Contact information:'#13#10 + - 'E-mail: ceefour@gauldong.net'#13#10 + - 'Web: http://wincachegrind.sourceforge.net/'#13#10 + + 'Web: http://ceefour.github.io/wincachegrind/'#13#10 + + 'E-mail: hendy@hendyirawan.com'#13#10 + #13#10 + - 'This program is licensed under GNU General Public License version ' + - '2 or later.'#13#10 + - 'See GPL.txt for more information.', mtInformation, [mbOK], 0); + 'This program is licensed under GNU General Public License version v3.'#13#10 + + 'See LICENSE file for more information.', mtInformation, [mbOK], 0); finally FreeAndNil(VI); end;