In order for Piyasa to write out data detailing execution time, function marcos need to be added to the code. You can do this manually or automatically as explained below. Some defines however must be made manually and are covered in Step 2: Compiling and Running Marked-up code.
Manual Marking.
There are 4 functions you can use to have Piyasa gather information about your code. They are piFunctIn(), piFunctOut(), piUserStart(), and piUserEnd(). These are all defined in <edivision/piyasa.h>, which must be included in your sourcecode.
piFunctIn() and piFunctOut() are used at the start and end of a function. They take a single argument, which is a function identification number. You may use any number you like, but it is required that each function inside the same source file have a unique nummber. Programs which mark up the source manually will normally start at 1000, so if you wish to use both you are safe using numbers under 1000. You can, but it is not necessary, give a unique number to each function in every source file. Here is an example of how this is used:
int main(int argc, char **argv) {piFunctIn(1002);{You can see here how piFunctIn() and piFunctOut() are used with a function definition, return statement, and end of function marker.return piFunctOut(1002), 0;
} piFunctOut(1002);}
piUserStart() and piUserEnd() can be added anywhere in your code you like. Piyasa will begin profiling at piUserStart() and end at piUserEnd(). These can be used to wrap and monitor things like inner loops. Each of these take a single argument, which is a unique text lable. The text lable must be unique for all source files compiled together.
piUserStart("bar_loop");Here, we want to check the performance of some useless loop, which is called 'bar_loop'. The formatted output will refer to this by the label.i=rand()&0xFFFFFF;
for(f=0;f<i;f++);
piUserEnd("bar_loop");
Automatic Marking
Automatic marking programs take a source file on stdin and output a marked-up version on stdout. Only function blocks are marked for profiling. Currently, the only supplied auto-marker is piyCAuto, which is for C files. (In the future hopefully someone will extend Piyasa and create a VP auto-marker.) It will add the necessary #includes and piFunctIn()s and piFunctOut()s. You may still need to add defines depending on how complex your compile is. See the included test directory for examples of how to use piyCauto.
Step 2: Compiling and Running Marked-Up Code
There are several compiler defines that control Piyasa. At a minimum you must define PROFILE or PIYASA, otherwise Piyasa will default to inactive and no profiling code will be included in the compiled software.
PIYASA_OUTWhen the code is ready to compile, create an executable and run it. Be sure if your PIYASA_OUT is set to stdout or stderr that you redirect your output to a file. Output text which makes it into the file should not cause a problem. Your program will run quite a bit slower due to the file i/o, however it does not effect the relative performance of profiled blocks of code, especially when then are executed multiple times.This controls where the Piysasa data will be written. The default is to stderr for redirection to a file during execution. You can redefine this to stdout, or a global file pointer for an initialized file or stream. This variable is passed as the output stream to fprintf().
PIYASA_FSNUM
This is defined as an integer and is added to your piFunctIn()/Out() unique ID numbers. This define allows multiple files compiled together which have conflicting unique ID function numbers to be resolved manually. In the example above where main() is tagged as 1002, if PIYASA_FSNUM were defined before it as 200, it would actually have the value 1202. Using the automarker can generate conflicting numbers so it is a good idea to ifdef->undef->def a unique PIYASA_FSNUM for each source file you which to profile in. Make sure you number is large enough to not cause additional conflicts.
Step 3: Processing the Piyasa Output
After running you should have a Piyasa raw output file (.piy). It will look something like this:
Sf|160806023262000|00001002|mainIt may also be quite large (several hundred megs). There are filters that will convert this file into something more useful. Don't worry if your .piy file has text that is part of your program's normal output. The filters will simply issue a warning on stderr saying they can't understand the line. Filters take the input file on stdin and output the formatted report on stdout. Currently Piyasa has 2 filtering programs: piy2text and piy2csv.
Sf|160806023285000|00001000|foo
Ef|160806023363000|00001000|foo
Sf|160806023373000|00001001|bar
Su|160806023387000|bar_loop|bar
Eu|160806067145000|bar_loop|bar
Ef|160806067169000|00001001|bar
Sf|160806067178000|00001000|foo
Ef|160806067217000|00001000|foo
Sf|160806067227000|00001001|bar
Su|160806067240000|bar_loop|bar
Eu|160806091166000|bar_loop|bar
Piy2text will process the file and give you a simple text summary. Here is an example of the output:
4 itemsHere you can see each function call and user block. The first character of each line is an 'f' for a function block, or a 'u' for a user block. After that.is the name of the function for a function block, or the name of the user block with the function it occurs inside of. Next is the number of times the function was encountered or called. Then the average, min, and maximum time it took to execute the code. (NOTE: An extremely large 'max' may be the result of file I/O issues.) The total time spent in the code can be calulated by multiplying calls by avg.
f: main calls:1 avg:328904000ns min:328904000ns max:328904000ns
f: foo calls:11 avg:22090ns min:13000ns max:78000ns
f: bar calls:10 avg:32845100ns min:14395000ns max:47567000ns
u: bar_loop (bar) calls:10 avg:32822200ns min:14373000ns max:47547000ns
Piy2cvs exports a comma-separated value file suitable for importing into a spreadsheep application. Here is an example of one imported into Kspread:
It is strongly recommended that the supplied parser be used, but if you wish to create your own documentation on the output follows.
Piyasa output format:
Sf|160806023262000|00001002|mainIn the above example output you can see each line has 4 fields separated by a vertical bar.
Sf|160806023285000|00001000|foo
Ef|160806023363000|00001000|foo
Sf|160806023373000|00001001|bar
Su|160806023387000|bar_loop|bar
Eu|160806067145000|bar_loop|bar
Ef|160806067169000|00001001|bar
Sf|160806067178000|00001000|foo
Ef|160806067217000|00001000|foo
Sf|160806067227000|00001001|bar
Su|160806067240000|bar_loop|bar
Eu|160806091166000|bar_loop|bar
The first is a 2 character code that identifies the type of entry. The first character is 'S' for start or 'E' for end and 'f' is for function and 'u' for user block.
The second field is a long (64-bit) number which is a timestamp.
The third field is either a unique ID number for a function entry (f), or the unique label for a user entry (u).
The Last field is the name of the function in which the entry was generated.
Using Piyasa with VP is very similar to its use in C. There are only a couple of differenced. First, you need to include 'edivision/piyasa.inc'. The user blocks function exactly the same as with C, however, the function blocks need to be passed the function name rather than the ID number. (This is because currently there is no VP equal for the c preprocessor's __FUNCTION__ define.).