First public contribution.
1 // Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies).
2 // All rights reserved.
3 // This component and the accompanying materials are made available
4 // under the terms of the License "Eclipse Public License v1.0"
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
19 #include "distribution.h"
26 #else //!__MSVCDOTNET__
29 #endif //__MSVCDOTNET__
33 Analyse::TAction Analyse::sAction;
34 Analyse::TFormat Analyse::sFormat;
35 Analyse::TPartition Analyse::sPartition;
36 int Analyse::sOptions;
37 std::vector<const char*> Analyse::sTraces;
38 const char* Analyse::sRomFile;
39 const char* Analyse::sThread;
40 const char* Analyse::sDll;
41 const char* Analyse::sFunction;
42 unsigned Analyse::sBase;
43 unsigned Analyse::sLim;
44 unsigned Analyse::sBuckets = 100;
45 unsigned Analyse::sBucketSize;
46 double Analyse::sCutOff;
47 unsigned Analyse::sBeginSample;
48 unsigned Analyse::sEndSample = 0xffffffffu;
55 void PartitionByDll::File(const char* aName)
60 bool PartitionByDll::Symbol(const char*, PC aPc, int)
62 bool is_added = false;
65 if (iLastFile && Analyse::Match(iLastFile, iMatch))
67 Add(iLastFileAddress, aPc, iLastFile);
70 iLastFile = iCurrentFile;
71 iLastFileAddress = aPc;
78 PartitionByFunction::PartitionByFunction(const char* aFile, const char* aFunction)
79 :iFile(aFile), iFunction(aFunction), iActive(false)
82 void PartitionByFunction::File(const char* aName)
84 iActive = Analyse::Match(aName, iFile);
87 bool PartitionByFunction::Symbol(const char* aSymbol, PC aPc, int aLength)
89 bool is_added = false;
90 if (iActive && Analyse::Match(aSymbol, iFunction))
92 Add(aPc, aPc + aLength, aSymbol);
100 class FindFunction : public SymbolFile::Parser
103 FindFunction(const char* aFile, const char* aFunction);
104 void File(const char* aName);
105 bool Symbol(const char* aName, PC aPc, int aLength);
106 void Done(PC aFirstPc=0, PC aLastPc=0, int aModuleId=0);
109 const char* iFunction;
116 FindFunction::FindFunction(const char* aFile, const char* aFunction)
117 :iFile(aFile), iFunction(aFunction), iActive(false), iPc(0)
120 void FindFunction::File(const char* aName)
123 iActive = Analyse::Match(aName, iFile);
126 bool FindFunction::Symbol(const char* aSymbol, PC aPc, int aLength)
128 bool is_added = false;
129 if (iPc == 0 && iActive && Analyse::Match(aSymbol, iFunction))
138 void FindFunction::Done(PC aFirstPc, PC aLastPc, int aModuleId)
141 //}; // local namepsace
146 int main(int argc,char *argv[])
148 switch(Analyse::ProcessCommandLine(argc,argv))
151 Analyse::ExplainUsage();
154 Analyse::ExplainConfigUsage();
163 void Analyse::Information()
165 cout << "\nEPOC Profile Analyser Version " << MajorVersion << '.' \
166 << setw(2) << MinorVersion << "(build " << setw(3) << setfill('0') << Build \
167 << ")\nCopyright (c) Symbian Limited 2000. All rights reserved.\n\n" << flush;
170 void Analyse::ExplainUsage()
173 cout << "Usage: Analyse [options] tracefile\n" \
174 " -h display this information\n" \
175 " -l generate a trace listing\n" \
176 " -p generate a profile distribution\n" \
177 " -v generate a activity trace\n" \
178 " -r <symbols> supply a Rom symbol file\n" \
179 " -s<range> restrict the profile to the samples specified\n" \
180 " This is specified either as <start>-<end> or\n" \
181 " as <start>+<length> in decimal\n" \
182 " -n include NULL thread\n" \
183 " -t <thread> profile threads matching the pattern\n" \
184 " -d <dll> profile DLL (or EXE) matching the pattern\n" \
185 " -f <function> profile the function matching the pattern\n" \
186 " -a<range> profile the address range specified\n" \
187 " This is specified either as <start>-<end> or\n" \
188 " as <start>+<length> in hexadecimal\n" \
189 " -bd partition the profile by dll/exe\n" \
190 " -bf partition the profile by function\n" \
191 " -bs<n> partition the profile into buckets of size n\n" \
192 " -bn<n> partition the profile into approx. n buckets\n" \
193 " -c<n> set the cutoff value for discarding output\n" \
194 " -m... setformat options:\n" \
195 " p|s|x use percentages/samples/excel for output\n" \
196 " z output zero values instead of blanks\n" \
197 " t do not show thread break-down\n" \
198 " o do not include the <other> bucket\n" \
199 " -z <rofs> supply a ROFS symbol file\n" \
200 " -o <oby> supply an OBY file\n" \
201 " -x <config> supply a config file\n" \
202 " -h config display an example of config file\n" \
206 void Analyse::ExplainConfigUsage()
209 cout << "Example of config file:" << endl << endl;
210 cout << "[Common]" << endl;
211 cout << "TraceFile=PROFILER.DAT" << endl;
212 cout << "Mode=listing|profile|activity" << endl;
213 cout << "SymbolFile=core4r.bin.symbol" << endl;
214 cout << "Range=100-200 | 100+100" << endl;
215 cout << "IncludeNullThread=0|1" << endl;
216 cout << "[Profile]" << endl;
217 cout << "Thread=" << endl;
218 cout << "Dll=" << endl;
219 cout << "Function=" << endl;
220 cout << "Range=1f1a+20 | 1f1a-1f3a" << endl;
221 cout << "[Partition]" << endl;
222 cout << "Mode=dll|function" << endl;
223 cout << "BucketSize=" << endl;
224 cout << "NumberOfBuckets=" << endl;
225 cout << "[Format]" << endl;
226 cout << "Mode=percentages|samples|excel" << endl;
227 cout << "ZeroValues=0|1" << endl;
228 cout << "NoOthers=0|1" << endl;
229 cout << "TotalOnly=0|1" << endl;
230 cout << "[NonXIP]" << endl;
231 cout << "ObyFile1=myrofs.oby" << endl;
232 cout << "RofsSymbolFile1=rofs.bin.symbol" << endl;
243 const static Entry KOptions[];
244 static int Compare(const char* aLhs, const char* aRhs);
246 static int Get(istrstream& aStr);
250 const Options::Entry Options::KOptions[] =
278 inline int min(int a, int b)
280 return a < b ? a : b;
283 int Options::Compare(const char* aLhs, const char* aRhs)
285 int len = min(strlen(aLhs), strlen(aRhs));
286 return strnicmp(aLhs, aRhs, len);
289 int Options::Get(istrstream& aStr)
291 int pos = aStr.tellg();
292 const char* s = aStr.str() + pos;
296 int l = 0, r = sizeof(KOptions)/sizeof(KOptions[0]);
299 int m = (l + r ) >> 1;
300 const Entry& e = KOptions[m];
301 int k = Compare(s, e.iName);
309 aStr.ignore(strlen(e.iName));
318 int Analyse::ProcessCommandLine(int argc, char ** argv)
320 int initial_argc = argc;
321 char ** initial_argv = argv;
322 // added 2-nd pass. on the 1-st just look for config file
323 for(int pass = 0;pass < 2;pass++)
329 istrstream arg(*++argv);
331 if (c != '/' && c != '-')
333 if (pass == 0) continue;
335 sTraces.push_back(arg.str());
338 c = Options::Get(arg);
339 if (tolower(c) != 'x' && pass == 0)
343 case 'h': case 'H': case '?':
344 if (--argc > 0 && !stricmp(*++argv,"config"))
358 Abort("No symbol file specified for option '-r'");
367 sEndSample += sBeginSample;
376 Abort("No thread name specified for option '-t'");
381 Abort("No DLL name specified for option '-d'");
386 Abort("No function name specified for option '-f'");
390 sOptions |= EAddress;
400 switch (c = Options::Get(arg))
406 sPartition = EFunction;
409 sPartition = EBuckets;
410 arg >> dec >> sBuckets;
414 arg >> dec >> sBucketSize;
422 while ((c = Options::Get(arg)) != EOF)
439 sOptions |= ENoOther;
442 sOptions |= ETotalOnly;
452 Abort("No OBY file name specified for option '-o'");
453 gNonXIP.AddObyFile(*++argv);
457 Abort("No ROFS symbol file name specified for option '-z'");
458 gNonXIP.AddSymbolFile(*++argv);
462 Abort("No config file name specified for option '-x'");
465 switch(ProcessCfgFile(*++argv))
468 Abort("Error no config file name specified for option '-x'");
470 Abort("Error in config file");
476 default: // unrecognised option
480 if (!arg || arg.get() != EOF)
482 cerr << "Unrecognised option \'" << arg.str() << '\'' << endl;
488 Abort("No trace files specified");
489 return sTraces.size() != 1;
492 CodeSpace* Analyse::CreateCodeSpace(SymbolFile* aSymbols, NonXIP *aNonXIP)
494 if (Option(EAddress))
497 if (Partition() == ESize)
500 size = (sLim - sBase) / sBuckets;
501 return new AddressCodeSpace(sBase, sLim, size, AddressCodeSpace::EAbsolute);
504 MappedCodeSpace * mapped_code_space = 0;
507 MappedCodeSpace* mapped_code_space = new MappedCodeSpace();
509 aNonXIP->SetMappedCodeSpace(mapped_code_space);
510 return mapped_code_space;
524 sPartition = EFunction;
530 PartitionByDll p(sDll);
531 mapped_code_space = new MappedCodeSpace(*aSymbols,p);
533 aNonXIP->SetMappedCodeSpace(mapped_code_space);
534 return mapped_code_space;
538 PartitionByFunction p(sDll, sFunction);
539 mapped_code_space = new MappedCodeSpace(*aSymbols,p);
541 aNonXIP->SetMappedCodeSpace(mapped_code_space);
542 return mapped_code_space;
547 sPartition = EFunction;
550 FindFunction f(sDll, sFunction);
554 cerr << "Cannot find function '" << sFunction << '\'';
556 cerr << " in '" << sDll << '\'';
560 unsigned size = (Partition() == ESize) ? sBucketSize : f.iLength / sBuckets;
561 return new AddressCodeSpace(f.iPc, f.iPc + f.iLength, size, AddressCodeSpace::ERelative);
568 Sampler* Analyse::CreateSampler(SymbolFile* aSymbols, NonXIP *aNonXIP)
574 MappedCodeSpace * mapped_code_space = 0;
576 //return new Tracer(0);
577 mapped_code_space = new MappedCodeSpace();
580 PartitionByFunction p(0, 0);
581 mapped_code_space = new MappedCodeSpace(*aSymbols,p);
583 if (aNonXIP) aNonXIP->SetMappedCodeSpace(mapped_code_space);
584 return new Tracer(mapped_code_space);
588 CodeSpace * code_space = CreateCodeSpace(aSymbols, aNonXIP);
589 return new Distribution(*code_space, sCutOff);
592 return new Activity(Partition() == ESize ? sBucketSize : 100, sBeginSample, sCutOff);
599 // The main part of the program
604 trace.Load(sTraces[0], sBeginSample, sEndSample);
605 // create map of original/segment names
606 gNonXIP.CreateNamesMap();
608 SymbolFile* symbols = 0;
610 symbols = new SymbolFile(sRomFile);
611 Sampler* sampler = CreateSampler(symbols, &gNonXIP);
612 trace.Decode(*sampler, &gNonXIP);
614 // NonXIP footer messages
615 cout << endl << "Row buffer errors:" << gNonXIP.iRowBufferErrors;
616 cout << " Cook buffer errors:" << gNonXIP.iCookBufferErrors;
618 if (gNonXIP.iReportMask & NonXIP::ENonXip)
622 if (gNonXIP.iReportMask & NonXIP::ENodebugSupport)
623 cout << " No debug support from Kernel";
630 bool Analyse::Match(const char* aString, const char* aMatch)
633 // If match string is 0, then matches everything
639 const char* star = strchr(aMatch, '*');
641 return (stricmp(aString, aMatch) == 0);
643 int mlen = star - aMatch;
644 if (strnicmp(aString, aMatch, mlen) != 0)
647 const char* end = aString + strlen(aString);
653 star = strchr(aMatch, '*');
655 return (stricmp(end - strlen(aMatch), aMatch) == 0);
656 mlen = star - aMatch;
657 const char* lim = end - mlen;
662 if (strnicmp(aString, aMatch, mlen) == 0)
669 void Analyse::Abort(char const* aMessage)
671 cerr << aMessage << endl;
675 void Analyse::Abort()
680 void Analyse::Corrupt(char const* aMessage)
682 // terminate after detecting a fatal corruption error
685 cerr << "\nfatal error: " << aMessage << "\ncannot continue\n" << flush;
689 ostream& Analyse::Error()
691 return cerr << "error: ";
694 ostream& Analyse::Warning()
696 return cerr << "warning: ";