├── Predict ├── Exception.php ├── Vector.php ├── Geodetic.php ├── ObsSet.php ├── QTH.php ├── DeepArg.php ├── Pass.php ├── SGSDPStatic.php ├── PassDetail.php ├── DeepStatic.php ├── Solar.php ├── Math.php ├── SGPObs.php ├── Time.php ├── TLE.php └── Sat.php ├── examples ├── google_maps_iss.png ├── pass_polar_plot.png ├── iss.tle ├── update_iss_tle.php ├── findsun.php ├── solar_position.php ├── benchmark.php └── visible_passes.php ├── xhprof_lib ├── jquery │ ├── indicator.gif │ ├── jquery.tooltip.css │ ├── jquery.autocomplete.css │ ├── jquery.tooltip.js │ └── jquery.autocomplete.js ├── docs │ ├── sample-flat-view.jpg │ ├── sample-callgraph-image.jpg │ ├── sample-parent-child-view.jpg │ ├── sample-diff-report-flat-view.jpg │ ├── sample-diff-report-parent-child-view.jpg │ └── index.html ├── list.php ├── typeahead.php ├── css │ └── xhprof.css ├── display │ └── typeahead_common.php ├── index.php ├── callgraph.php ├── EC │ └── XHProf.php ├── utils │ ├── xhprof_runs.php │ └── callgraph_utils.php └── js │ └── xhprof_report.js ├── tests ├── test-001.tle ├── test-002.tle ├── test-001.php ├── test-002.php └── Table.php ├── composer.json ├── README.md ├── generatePackage.php └── package.xml /Predict/Exception.php: -------------------------------------------------------------------------------- 1 | lat = 37.786759; 19 | $qth->lon = -122.405162; 20 | $qth->alt = 10; // Altitude above sea level in meters 21 | 22 | $sunInfo = Predict_Solar::FindSun($qth, $daynum); 23 | 24 | $output = array( 25 | 'elevation' => $sunInfo->el, 26 | 'azimuth' => $sunInfo->az, 27 | 'timestamp' => $time 28 | ); 29 | 30 | // output results 31 | echo json_encode($output); 32 | -------------------------------------------------------------------------------- /Predict/SGSDPStatic.php: -------------------------------------------------------------------------------- 1 | clear(); 12 | header('Location: ' . $_SERVER['PHP_SELF']); 13 | } 14 | ?> 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 || Run ID | Date | 30 |
| 37 | |
XHProf is a hierarchical profiler for PHP. It reports
35 | function-level call counts and inclusive and
36 | exclusive metrics such as wall (elapsed)
37 | time, CPU time and memory usage. A function's profile can be broken
38 | down by callers or callees. The raw data collection component is
39 | implemented in C as a PHP Zend extension called
40 | xhprof. XHProf has a simple HTML based user
41 | interface (written in PHP). The browser based UI for viewing profiler
42 | results makes it easy to view results or to share results with peers.
43 | A callgraph image view is also supported.
44 |
45 |
XHProf reports can often be helpful in understanding the structure 46 | of the code being executed. The hierarchical nature of the reports can 47 | be used to determine, for example, what chain of calls led to a 48 | particular function getting called. 49 | 50 |
XHProf supports ability to compare two runs (a.k.a. "diff" reports) 51 | or aggregate data from multiple runs. Diff and aggregate reports, much 52 | like single run reports, offer "flat" as well as "hierarchical" views 53 | of the profile. 54 | 55 |
XHProf is a light-weight instrumentation based profiler. During the 56 | data collection phase, it keeps track of call counts and inclusive 57 | metrics for arcs in the dynamic callgraph of a program. It computes 58 | exclusive metrics in the reporting/post processing phase. XHProf 59 | handles recursive functions by detecting cycles in the callgraph at 60 | data collection time itself and avoiding the cycles by giving unique 61 | depth qualified names for the recursive invocations. 62 |
63 | 64 |XHProf's light-weight nature and aggregation capabilities make it 65 | well suited for collecting "function-level" performance statistics 66 | from production environments. [See additional notes for use in production.] 68 | 69 |
XHProfLive (not part of the open source kit), for example, is a 73 | system-wide performance monitoring system in use at Facebook that is 74 | built on top of XHProf. XHProfLive continually gathers function-level 75 | profiler data from production tier by running a sample of page 76 | requests under XHProf. XHProfLive then aggregates the profile data 77 | corresponding to individual requests by various dimensions such a 78 | time, page type, and can help answer a variety of questions such as: 79 | What is the function-level profile for a specific page? How expensive 80 | is function "foo" across all pages, or on a specific page? What 81 | functions regressed most in the last hour/day/week? What is the 82 | historical trend for execution time of a page/function? and so on. 83 | 84 |
Originally developed at Facebook, XHProf was open sourced in Mar, 2009.
89 | 90 | 91 | 92 | 93 | 94 |XHProf provides: 97 | 98 |
Provides function-level summary information such number of calls, 102 | inclusive/exclusive wall time, memory usage, and CPU time. 103 | 104 |
For each function, it provides a breakdown of calls and times per 108 | parent (caller) & child (callee), such as: 109 | 110 |
You may want to compare data from two XHProf runs for various 123 | reasons-- to figure out what's causing a regression between one 124 | version of the code base to another, to evaluate the performance 125 | improvement of a code change you are making, and so on. 126 | 127 |
A diff report takes two runs as input and provides both flat 128 | function-level diff information, and hierarchical information 129 | (breakdown of diff by parent/children functions) for each function. 130 | 131 |
The "flat" view (sample screenshot) in the diff report points out the top 133 | regressions & improvements. 134 | 135 |
Clicking on functions in the "flat" view of the diff report, leads 136 | to the "hierarchical" (or parent/child) diff view of a function (sample screenshot). We can get a 138 | breakdown of the diff by parent/children functions. 139 | 140 | 141 |
The profile data can also be viewed as a callgraph. The callgraph 145 | view highlights the critical path of the program. 146 | 147 | 148 |
XHProf's memory profile mode helps track functions that 151 | allocate lots of memory. 152 | 153 |
It is worth clarifying that that XHProf doesn't strictly track each 154 | allocation/free operation. Rather it uses a more simplistic 155 | scheme. It tracks the increase/decrease in the amount of memory 156 | allocated to PHP between each function's entry and exit. It also 157 | tracks increase/decrease in the amount of peak memory allocated to 158 | PHP for each function. 159 | 160 |
include, include_once, require and
161 | require_once operations as if they were functions. The name of
162 | the file being included is used to generate the name for these "fake" functions.
164 |
165 |
166 | main(): a fictitious function that is at the root of the call graph.
188 |
189 |
190 | load::<filename>
191 | and run_init::<filename>:
192 |
193 | XHProf tracks PHP include/require operations as
194 | function calls.
195 |
196 |
For example, an include "lib/common.php"; operation will 197 | result in two XHProf function entries: 198 | 199 |
load::lib/common.php - This represents the work done by the
202 | interpreter to compile/load the file. [Note: If you are using a PHP
203 | opcode cache like APC, then the compile only happens on a cache miss
204 | in APC.]
205 |
206 | run_init::lib/common.php - This represents
207 | initialization code executed at the file scope as a result of the
208 | include operation.
209 |
210 | foo@<n>: Implies that this is a
213 | recursive invocation of foo(), where <n> represents
214 | the recursion depth. The recursion may be direct (such as due to
215 | foo() --> foo()), or indirect (such as
216 | due to foo() --> goo() --> foo()).
217 |
218 | True hierarchical profilers keep track of a full call stack at 224 | every data gathering point, and are later able to answer questions 225 | like: what was the cost of the 3rd invokation of foo()? or what was 226 | the cost of bar() when the call stack looked like 227 | a()->b()->bar()? 228 | 229 |
230 | 231 |XHProf keeps track of only 1-level of calling context and is 232 | therefore only able to answer questions about a function looking 233 | either 1-level up or 1-level down. It turns out that in practice this 234 | is sufficient for most use cases. 235 |
236 | 237 |To make this more concrete, take for instance the following 238 | example. 239 |
240 | 241 |242 | Say you have: 243 | 1 call from a() --> c() 244 | 1 call from b() --> c() 245 | 50 calls from c() --> d() 246 |247 | 248 |
While XHProf can tell you that d() was called from c() 50 times, it 249 | cannot tell you how many of those calls were triggered due to a() 250 | vs. b(). [We could speculate that perhaps 25 were due to a() and 25 251 | due to b(), but that's not necessarily true.] 252 |
253 | 254 |In practice however, this isn't a very big limitation. 255 |
256 | 257 |The extension lives in the "extension/" sub-directory. 260 | 261 |
Note: A windows port hasn't been implemented yet. We have
264 | tested xhprof on Linux/FreeBSD so far.
265 |
266 |
Version 0.9.2 and above of XHProf is also expected to work on Mac 267 | OS. [We have tested on Mac OS 10.5.] 268 | 269 |
Note: XHProf uses the RDTSC instruction (time stamp counter)
270 | to implement a really low overhead timer for elapsed time. So at the
271 | moment xhprof only works on x86 architecture.
272 | Also, since RDTSC values may not be synchronized across CPUs,
273 | xhprof binds the program to a single CPU during the
274 | profiling period.
275 |
276 |
XHProf's RDTSC based timer functionality doesn't work correctly if 277 | SpeedStep technology is turned on. This technology is available on 278 | some Intel processors. [Note: Mac desktops and laptops typically have 279 | SpeedStep turned on by default. To use XHProf, you'll need to disable 280 | SpeedStep.] 281 | 282 |
The steps 285 | below should work for Linux/Unix environments. 286 | 287 | 288 |
289 | % cd <xhprof_source_directory>/extension/ 290 | % phpize 291 | % ./configure --with-php-config=<path to php-config> 292 | % make 293 | % make install 294 | % make test 295 |296 | 297 | 298 |
php.ini file: You can update your 299 | php.ini file to automatically load your extension. Add the following 300 | to your php.ini file. 301 | 302 |
303 | [xhprof] 304 | extension=xhprof.so 305 | ; 306 | ; directory used by default implementation of the iXHProfRuns 307 | ; interface (namely, the XHProfRuns_Default class) for storing 308 | ; XHProf runs. 309 | ; 310 | xhprof.output_dir=<directory_for_storing_xhprof_runs> 311 |312 | 313 | 314 |
Test generating raw profiler data using a sample test program like: 317 | 318 |
foo.php 320 |
321 | <?php
322 |
323 | function bar($x) {
324 | if ($x > 0) {
325 | bar($x - 1);
326 | }
327 | }
328 |
329 | function foo() {
330 | for ($idx = 0; $idx < 2; $idx++) {
331 | bar($idx);
332 | $x = strlen("abc");
333 | }
334 | }
335 |
336 | // start profiling
337 | xhprof_enable();
338 |
339 | // run program
340 | foo();
341 |
342 | // stop profiler
343 | $xhprof_data = xhprof_disable();
344 |
345 | // display raw xhprof data for the profiler run
346 | print_r($xhprof_data);
347 |
348 |
349 |
350 | Run the above test program: 351 | 352 |
353 | % php -dextension=xhprof.so foo.php 354 |355 | 356 |
You should get an output like: 357 | 358 |
359 | Array 360 | ( 361 | [foo==>bar] => Array 362 | ( 363 | [ct] => 2 # 2 calls to bar() from foo() 364 | [wt] => 27 # inclusive time in bar() when called from foo() 365 | ) 366 | 367 | [foo==>strlen] => Array 368 | ( 369 | [ct] => 2 370 | [wt] => 2 371 | ) 372 | 373 | [bar==>bar@1] => Array # a recursive call to bar() 374 | ( 375 | [ct] => 1 376 | [wt] => 2 377 | ) 378 | 379 | [main()==>foo] => Array 380 | ( 381 | [ct] => 1 382 | [wt] => 74 383 | ) 384 | 385 | [main()==>xhprof_disable] => Array 386 | ( 387 | [ct] => 1 388 | [wt] => 0 389 | ) 390 | 391 | [main()] => Array # fake symbol representing root 392 | ( 393 | [ct] => 1 394 | [wt] => 83 395 | ) 396 | 397 | ) 398 |399 | 400 |
Note: The raw data only contains "inclusive" metrics. For 401 | example, the wall time metric in the raw data represents inclusive 402 | time in microsecs. Exclusive times for any function are computed 403 | during the analysis/reporting phase. 404 | 405 |
Note: By default only call counts & elapsed time is profiled. 406 | You can optionally also profile CPU time and/or memory usage. Replace, 407 | 408 |
409 | xhprof_enable(); 410 |411 | in the above program with, for example: 412 |
413 | xhprof_enable(XHPROF_FLAGS_CPU + XHPROF_FLAGS_MEMORY); 414 |415 | 416 |
You should now get an output like: 417 | 418 |
419 | Array 420 | ( 421 | [foo==>bar] => Array 422 | ( 423 | [ct] => 2 # number of calls to bar() from foo() 424 | [wt] => 37 # time in bar() when called from foo() 425 | [cpu] => 0 # cpu time in bar() when called from foo() 426 | [mu] => 2208 # change in PHP memory usage in bar() when called from foo() 427 | [pmu] => 0 # change in PHP peak memory usage in bar() when called from foo() 428 | ) 429 | 430 | [foo==>strlen] => Array 431 | ( 432 | [ct] => 2 433 | [wt] => 3 434 | [cpu] => 0 435 | [mu] => 624 436 | [pmu] => 0 437 | ) 438 | 439 | [bar==>bar@1] => Array 440 | ( 441 | [ct] => 1 442 | [wt] => 2 443 | [cpu] => 0 444 | [mu] => 856 445 | [pmu] => 0 446 | ) 447 | 448 | [main()==>foo] => Array 449 | ( 450 | [ct] => 1 451 | [wt] => 104 452 | [cpu] => 0 453 | [mu] => 4168 454 | [pmu] => 0 455 | ) 456 | 457 | [main()==>xhprof_disable] => Array 458 | ( 459 | [ct] => 1 460 | [wt] => 1 461 | [cpu] => 0 462 | [mu] => 344 463 | [pmu] => 0 464 | ) 465 | 466 | [main()] => Array 467 | ( 468 | [ct] => 1 469 | [wt] => 139 470 | [cpu] => 0 471 | [mu] => 5936 472 | [pmu] => 0 473 | ) 474 | 475 | ) 476 |477 | 478 |
Skipping builtin functions during profiling 479 | 480 |
By default PHP builtin functions (such as strlen) are
481 | profiled. If you do not want to profile builtin functions (to either
482 | reduce the overhead of profiling further or size of generated raw
483 | data), you can use the XHPROF_FLAGS_NO_BUILTINS
484 | flag as in for example:
485 |
486 |
487 | // do not profile builtin functions 488 | xhprof_enable(XHPROF_FLAGS_NO_BUILTINS); 489 |490 | 491 | 492 |
Ignoring specific functions during profiling (0.9.2 or higher) 493 | 494 |
Starting with release 0.9.2 of xhprof, you can tell XHProf to
495 | ignore a specified list of functions during profiling. This allows you
496 | to ignore, for example, functions used for indirect function calls
497 | such as call_user_func and
498 | call_user_func_array. These intermediate functions
499 | unnecessarily complicate the call hierarchy and make the XHProf
500 | reports harder to interpret since they muddle the parent-child
501 | relationship for functions called indirectly.
502 |
503 |
To specify the list of functions to be ignored during profiling
504 | use the 2nd (optional) argument to xhprof_enable.
505 | For example,
506 |
507 |
508 |
509 |
510 | // elapsed time profiling; ignore call_user_func* during profiling
511 | xhprof_enable(0,
512 | array('ignored_functions' => array('call_user_func',
513 | 'call_user_func_array')));
514 |
515 | or,
516 |
517 | // elapsed time + memory profiling; ignore call_user_func* during profiling
518 | xhprof_enable(XHPROF_FLAGS_MEMORY,
519 | array('ignored_functions' => array('call_user_func',
520 | 'call_user_func_array')));
521 |
522 |
523 |
524 |
525 | The XHProf UI is implemented in PHP. The code resides in two
534 | subdirectories, xhprof_html/ and xhprof_lib/.
535 |
536 |
The xhprof_html directory contains the 3 top-level PHP pages.
537 |
538 |
index.php: For viewing a single run or diff report.
540 | callgraph.php: For viewing a callgraph of a XHProf run as an image.
541 | typeahead.php: Used implicitly for the function typeahead form
542 | on a XHProf report.
543 | The xhprof_lib directory contains supporting code for
546 | display as well as analysis (computing flat profile info, computing
547 | diffs, aggregating data from multiple runs, etc.).
548 |
549 |
Web server config: You'll need to make sure that the
550 | xhprof_html/ directory is accessible from your web server, and that
551 | your web server is setup to serve PHP scripts.
552 |
553 |
Managing XHProf Runs 554 | 555 |
Clients have flexibility in how they save the XHProf raw data 556 | obtained from an XHProf run. The XHProf UI layer exposes an interface 557 | iXHProfRuns (see xhprof_lib/utils/xhprof_runs.php) that clients can 558 | implement. This allows the clients to tell the UI layer how to fetch 559 | the data corresponding to a XHProf run. 560 | 561 |
The XHProf UI libaries come with a default file based 562 | implementation of the iXHProfRuns interface, namely 563 | "XHProfRuns_Default" (also in xhprof_lib/utils/xhprof_runs.php). 564 | This default implementation stores runs in the directory specified by 565 | xhprof.output_dir INI parameter. 566 | 567 |
A XHProf run must be uniquely identified by a namespace and a run 568 | id. 569 | 570 | 571 | 572 |
a) Saving XHProf data persistently: 573 | 574 |
Assuming you are using the default implementation
575 | XHProfRuns_Default of the
576 | iXHProfRuns interface, a typical XHProf run
577 | followed by the save step might look something like:
578 |
579 |
580 |
581 | // start profiling 582 | xhprof_enable(); 583 | 584 | // run program 585 | .... 586 | 587 | // stop profiler 588 | $xhprof_data = xhprof_disable(); 589 | 590 | // 591 | // Saving the XHProf run 592 | // using the default implementation of iXHProfRuns. 593 | // 594 | include_once $XHPROF_ROOT . "/xhprof_lib/utils/xhprof_lib.php"; 595 | include_once $XHPROF_ROOT . "/xhprof_lib/utils/xhprof_runs.php"; 596 | 597 | $xhprof_runs = new XHProfRuns_Default(); 598 | 599 | // Save the run under a namespace "xhprof_foo". 600 | // 601 | // **NOTE**: 602 | // By default save_run() will automatically generate a unique 603 | // run id for you. [You can override that behavior by passing 604 | // a run id (optional arg) to the save_run() method instead.] 605 | // 606 | $run_id = $xhprof_runs->save_run($xhprof_data, "xhprof_foo"); 607 | 608 | echo "---------------\n". 609 | "Assuming you have set up the http based UI for \n". 610 | "XHProf at some address, you can view run at \n". 611 | "http://<xhprof-ui-address>/index.php?run=$run_id&source=xhprof_foo\n". 612 | "---------------\n"; 613 | 614 |615 | 616 |
The above should save the run as a file in the directory specified
617 | by the xhprof.output_dir INI parameter. The file's
618 | name might be something like
619 | 49bafaa3a3f66.xhprof_foo; the two parts being the
620 | run id ("49bafaa3a3f66") and the namespace ("xhprof_foo"). [If you
621 | want to create/assign run ids yourself (such as a database sequence
622 | number, or a timestamp), you can explicitly pass in the run id to the
623 | save_run method.
624 |
625 |
626 |
b) Using your own implementation of iXHProfRuns 627 | 628 |
If you decide you want your XHProf runs to be stored differently 629 | (either in a compressed format, in an alternate place such as DB, 630 | etc.) database, you'll need to implement a class that implements the 631 | iXHProfRuns() interface. 632 | 633 |
You'll also need to modify the 3 main PHP entry pages (index.php,
634 | callgraph.php, typeahead.php) in the "xhprof_html/" directory to use
635 | the new class instead of the default class XHProfRuns_Default.
636 | Change this line in the 3 files.
637 |
638 |
639 | $xhprof_runs_impl = new XHProfRuns_Default(); 640 |641 | 642 |
You'll also need to "include" the file that implements your class in 643 | the above files. 644 | 645 | 646 |
Accessing runs from UI 647 | 648 |
a) Viewing a Single Run Report 649 | 650 |
To view the report for run id say <run_id> and namespace 651 | <namespace> use a URL of the form: 652 | 653 |
654 | http://<xhprof-ui-address>/index.php?run=<run_id>&source=<namespace>
655 |
656 |
657 |
For example, 658 |
659 | http://<xhprof-ui-address>/index.php?run=49bafaa3a3f66&source=xhprof_foo
660 |
661 |
662 |
663 |
b) Viewing a Diff Report 664 | 665 |
To view the report for run ids say <run_id1> and 666 | <run_id2> in namespace <namespace> use a URL of the form: 667 | 668 |
669 | http://<xhprof-ui-address>/index.php?run1=<run_id1>&run2=<run_id2>&source=<namespace>
670 |
671 |
672 |
c) Aggregate Report 673 | 674 |
You can also specify a set of run ids for which you want an aggregated view/report. 675 | 676 |
Say you have three XHProf runs with ids 1, 2 & 3 in namespace 677 | "benchmark". To view an aggregate report of these runs: 678 | 679 |
680 | http://<xhprof-ui-address>/index.php?run=1,2,3&source=benchmark
681 |
Weighted aggregations: Further suppose that the above three runs 684 | correspond to three types of programs p1.php, p2.php and p3.php that 685 | typically occur in a mix of 20%, 30%, 50% respectively. To view an 686 | aggregate report that corresponds to a weighted average of these runs 687 | using: 688 | 689 |
690 | http://<xhprof-ui-address>/index.php?run=1,2,3&wts=20,30,50&source=benchmark
691 |
Some observations/guidelines. Your mileage may vary: 699 | 700 |
We recommend using elapsed time + memory profiling mode in 708 | production. [Note: The additional overhead of memory profiling 709 | mode is really low.] 710 | 711 |
712 | // elapsed time profiling (default) + memory profiling 713 | xhprof_enable(XHPROF_FLAGS_MEMORY); 714 |715 |
To profile say 1/10000 of your requests, instrument the beginning of 722 | your request processing with something along the lines of: 723 | 724 |
725 | if (mt_rand(1, 10000) == 1) {
726 | xhprof_enable(XHPROF_FLAGS_MEMORY);
727 | $xhprof_on = true;
728 | }
729 |
730 |
731 | At the end of the request (or in a request shutdown function), you might 732 | then do something like: 733 | 734 |
735 | if ($xhprof_on) {
736 | // stop profiler
737 | $xhprof_data = xhprof_disable();
738 |
739 | // save $xhprof_data somewhere (say a central DB)
740 | ...
741 | }
742 |
743 |
744 | You can then rollup/aggregate these individual profiles by time
745 | (e.g., 5 minutely/hourly/daily basis), page/request type,or other
746 | dimensions using xhprof_aggregate_runs().
747 |
748 |
749 |
750 |
751 |
The xhprof extension also provides a very light weight sampling 754 | mode. The sampling interval is 0.1 secs. Samples record the full 755 | function call stack. The sampling mode can be useful if an extremely 756 | low overhead means of doing performance monitoring and diagnostics is 757 | desired. 758 | 759 |
The relevant functions exposed by the extension for using the
760 | sampling mode are xhprof_sample_enable() and
761 | xhprof_sample_disable().
762 |
763 |
764 |
[TBD: more detailed documentation on sampling mode.] 765 | 766 | 767 |
The xhprof_lib/utils/xhprof_lib.php file contains
770 | additional library functions that can be used for manipulating/
771 | aggregating XHProf runs.
772 |
773 |
For example: 774 | 775 |
xhprof_aggregate_runs():
779 | can be used to aggregate multiple XHProf runs into a single run. This
780 | can be helpful for building a system-wide "function-level" performance
781 | monitoring tool using XHProf. [For example, you might to roll up
782 | XHProf runs sampled from production periodically to generate hourly,
783 | daily, reports.]
784 |
785 | xhprof_prune_run(): Aggregating large number of
786 | XHProf runs (especially if they correspond to different types of
787 | programs) can result in the callgraph size becoming too large. You can
788 | use xhprof_prune_run function to prune the callgraph data
789 | by editing out subtrees that account for a very small portion of the
790 | total time.
791 |
792 | xhprof_html/jquery subdirectory.
807 |
808 | The HTML-based navigational interface for browsing profiler results 817 | is inspired by that of a similar tool that exists for Oracle's stored 818 | procedure language, PL/SQL. But that's where the similarity ends; the 819 | internals of the profiler itself are quite different. 820 | 821 |