Skip to content

Commit aae5edb

Browse files
authored
Implement perf stat --control for cgi (phpGH-22537)
perf stat --control allows the profiled process to enable and disable counters at runtime. This allows us to skip profiling startup and shutdown for more accurate results. The same already exists for valgrind. $ perf stat -D -1 --control fifo:/tmp/perfctl,/tmp/perfack -D -1 starts perf stat with counters disabled. --control makes perf stat connect to the /tmp/perfctl and /tmp/perfack fifo files. These need to exist when starting perf, so create them using mkfifo /tmp/perf{ctl,ack}. The ctl fifo is written to by cgi to enable/disable counters, whereas the ack fifo is written to by perf stat to acknowledge counters have been installed. Additionally, you'll need to set the set the PERF_STAT_CTL_FIFO and PERF_STAT_ACK_FIFO env variables for cgi to find the fifo files.
1 parent 9a14b9b commit aae5edb

2 files changed

Lines changed: 146 additions & 2 deletions

File tree

Zend/zend_perf_stat.h

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
/*
2+
+----------------------------------------------------------------------+
3+
| Zend Engine |
4+
+----------------------------------------------------------------------+
5+
| Copyright © Zend Technologies Ltd., a subsidiary company of |
6+
| Perforce Software, Inc., and Contributors. |
7+
+----------------------------------------------------------------------+
8+
| This source file is subject to the Modified BSD License that is |
9+
| bundled with this package in the file LICENSE, and is available |
10+
| through the World Wide Web at <https://www.php.net/license/>. |
11+
| |
12+
| SPDX-License-Identifier: BSD-3-Clause |
13+
+----------------------------------------------------------------------+
14+
| Authors: Ilija Tovilo <ilutov@php.net> |
15+
+----------------------------------------------------------------------+
16+
*/
17+
18+
#ifndef ZEND_PERF_STAT_H
19+
#define ZEND_PERF_STAT_H
20+
21+
#include "zend_portability.h"
22+
23+
# if !(HAVE_FCNTL_H && HAVE_SYS_SELECT_H && HAVE_SYS_STAT_H && HAVE_SYS_TIME_H && HAVE_UNISTD_H)
24+
static void zend_perf_stat_enable(void) {}
25+
static void zend_perf_stat_disable(void) {}
26+
# else
27+
28+
# include <fcntl.h>
29+
# include <sys/select.h>
30+
# include <sys/stat.h>
31+
# include <unistd.h>
32+
33+
# include "Zend/zend.h"
34+
35+
# define ZPS_CTL_FIFO_ENV "PERF_STAT_CTL_FIFO"
36+
# define ZPS_ACK_FIFO_ENV "PERF_STAT_ACK_FIFO"
37+
38+
static int ctl_fd = -2;
39+
static int ack_fd = -2;
40+
41+
static int zps_open_fifo(const char *env_name, int flags)
42+
{
43+
const char *path = getenv(env_name);
44+
45+
if (path == NULL || path[0] == '\0') {
46+
return -1;
47+
}
48+
49+
# ifdef O_CLOEXEC
50+
flags |= O_CLOEXEC;
51+
# endif
52+
int fd = open(path, flags | O_NONBLOCK);
53+
if (fd < 0) {
54+
fprintf(stderr, "Failed to open fifo %s\n", path);
55+
fflush(stderr);
56+
zend_bailout();
57+
}
58+
59+
struct stat st;
60+
if (fstat(fd, &st) != 0 || !S_ISFIFO(st.st_mode)) {
61+
close(fd);
62+
fprintf(stderr, "File %s is not a fifo\n", path);
63+
fflush(stderr);
64+
zend_bailout();
65+
}
66+
return fd;
67+
}
68+
69+
static void zps_init(void)
70+
{
71+
if (ctl_fd == -2) {
72+
ctl_fd = zps_open_fifo(ZPS_CTL_FIFO_ENV, O_WRONLY);
73+
}
74+
if (ack_fd == -2) {
75+
ack_fd = zps_open_fifo(ZPS_ACK_FIFO_ENV, O_RDONLY);
76+
}
77+
}
78+
79+
static void zps_wait_ack(void)
80+
{
81+
if (ack_fd < 0) {
82+
return;
83+
}
84+
85+
struct timeval timeout;
86+
timeout.tv_sec = 1;
87+
timeout.tv_usec = 0;
88+
89+
fd_set readfds;
90+
FD_ZERO(&readfds);
91+
FD_SET(ack_fd, &readfds);
92+
if (select(ack_fd + 1, &readfds, NULL, NULL, &timeout) <= 0) {
93+
return;
94+
}
95+
96+
char ack[sizeof("ack\n") - 1];
97+
ssize_t bytes_read;
98+
do {
99+
bytes_read = read(ack_fd, ack, sizeof(ack));
100+
} while (bytes_read > 0);
101+
}
102+
103+
static void zps_control(const char *command, size_t command_len)
104+
{
105+
zps_init();
106+
107+
if (ctl_fd < 0) {
108+
return;
109+
}
110+
111+
if (write(ctl_fd, command, command_len) != (ssize_t) command_len) {
112+
close(ctl_fd);
113+
ctl_fd = -1;
114+
return;
115+
}
116+
117+
zps_wait_ack();
118+
}
119+
120+
static void zend_perf_stat_enable(void)
121+
{
122+
static const char command[] = "enable\n";
123+
124+
zps_control(command, sizeof(command) - 1);
125+
}
126+
127+
static void zend_perf_stat_disable(void)
128+
{
129+
static const char command[] = "disable\n";
130+
131+
zps_control(command, sizeof(command) - 1);
132+
}
133+
134+
# endif
135+
#endif

sapi/cgi/cgi_main.c

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ int __riscosify_control = __RISCOSIFY_STRICT_UNIX_SPECS;
9595
# endif
9696
#endif
9797

98+
#include "zend_perf_stat.h"
99+
98100
#ifndef PHP_WIN32
99101
/* XXX this will need to change later when threaded fastcgi is implemented. shane */
100102
static struct sigaction act, old_term, old_quit, old_int;
@@ -1733,6 +1735,7 @@ int main(int argc, char *argv[])
17331735
int warmup_repeats = 0;
17341736
int repeats = 1;
17351737
int benchmark = 0;
1738+
bool perf_enabled = false;
17361739
#ifdef HAVE_GETTIMEOFDAY
17371740
struct timeval start, end;
17381741
#else
@@ -2441,14 +2444,16 @@ consult the installation file that came with this distribution, or visit \n\
24412444
}
24422445
} /* end !cgi && !fastcgi */
24432446

2444-
#ifdef HAVE_VALGRIND
24452447
if (warmup_repeats == 0) {
2448+
zend_perf_stat_enable();
2449+
perf_enabled = true;
2450+
#ifdef HAVE_VALGRIND
24462451
CALLGRIND_START_INSTRUMENTATION;
24472452
# ifdef HAVE_VALGRIND_CACHEGRIND_H
24482453
CACHEGRIND_START_INSTRUMENTATION;
24492454
# endif
2450-
}
24512455
#endif
2456+
}
24522457

24532458
/* request startup only after we've done all we can to
24542459
* get path_translated */
@@ -2568,6 +2573,10 @@ consult the installation file that came with this distribution, or visit \n\
25682573
SG(request_info).query_string = NULL;
25692574
}
25702575

2576+
if (perf_enabled) {
2577+
zend_perf_stat_disable();
2578+
perf_enabled = false;
2579+
}
25712580
#ifdef HAVE_VALGRIND
25722581
/* We're not interested in measuring shutdown */
25732582
CALLGRIND_STOP_INSTRUMENTATION;

0 commit comments

Comments
 (0)