Skip to content
Closed

Pfm #73

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/actions/apt-x64/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ runs:
libargon2-0-dev \
libmm-dev \
libsnmp-dev \
libpfm4 \
libpfm4-dev \
postgresql \
postgresql-contrib \
snmpd \
Expand Down
25 changes: 25 additions & 0 deletions .github/workflows/push.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ env:
CXX: ccache g++
jobs:
LINUX_X64:
if: false
services:
postgres:
image: postgres
Expand Down Expand Up @@ -89,6 +90,7 @@ jobs:
- name: Verify generated files are up to date
uses: ./.github/actions/verify-generated-files
LINUX_X32:
if: false
name: LINUX_X32_DEBUG_ZTS
runs-on: ubuntu-latest
container:
Expand Down Expand Up @@ -135,6 +137,7 @@ jobs:
-d opcache.enable_cli=1
-d opcache.jit_buffer_size=16M
MACOS_DEBUG_NTS:
if: false
runs-on: macos-11
steps:
- name: git checkout
Expand Down Expand Up @@ -172,6 +175,7 @@ jobs:
- name: Verify generated files are up to date
uses: ./.github/actions/verify-generated-files
WINDOWS:
if: false
strategy:
fail-fast: false
matrix:
Expand Down Expand Up @@ -215,3 +219,24 @@ jobs:
run: .github/scripts/windows/build.bat
- name: Test
run: .github/scripts/windows/test.bat
PFM:
name: "PFM"
runs-on: self-hosted
steps:
- name: git checkout
uses: actions/checkout@v3
- name: ./configure
run: |
./buildconf --force
./configure \
--disable-all \
--disable-debug \
--enable-cgi \
--enable-option-checking=fatal \
--enable-zts \
--prefix=/usr \
--with-pfm
- name: make
run: make -j$(/usr/bin/nproc) >/dev/null
- name: Test
run: sudo sapi/cgi/php-cgi -T1,10 Zend/bench.php
148 changes: 148 additions & 0 deletions sapi/cgi/cgi_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@ int __riscosify_control = __RISCOSIFY_STRICT_UNIX_SPECS;
# include "valgrind/callgrind.h"
#endif

#ifdef HAVE_PFM
# include <perfmon/pfmlib_perf_event.h>
#endif

#ifndef PHP_WIN32
/* XXX this will need to change later when threaded fastcgi is implemented. shane */
struct sigaction act, old_term, old_quit, old_int;
Expand Down Expand Up @@ -857,6 +861,127 @@ static void php_cgi_ini_activate_user_config(char *path, size_t path_len, const
}
/* }}} */

#ifdef HAVE_PFM
typedef struct {
struct perf_event_attr event_attr;
double instructions_sum;
uint32_t iterations;
int fd;
bool benchmark;
bool initialized;
} cgi_pfm_data;

static void cgi_pfm_terminate(cgi_pfm_data *data)
{
assert(data->initialized);
data->initialized = false;
data->benchmark = false;
pfm_terminate();
}

static void cgi_pfm_initialize(cgi_pfm_data *data)
{
assert(data->benchmark);
assert(!data->initialized);

data->fd = -1;

if (pfm_initialize() != PFM_SUCCESS) {
fprintf(stderr, "pfm_initialize() failed\n");
fflush(stderr);
data->benchmark = false;
return;
}

if (pfm_get_perf_event_encoding("instructions:u", PFM_PLM0|PFM_PLM3, &data->event_attr, NULL, NULL) != PFM_SUCCESS) {
fprintf(stderr, "pfm_get_perf_event_encoding() failed\n");
fflush(stderr);
cgi_pfm_terminate(data);
return;
}

data->event_attr.read_format = PERF_FORMAT_TOTAL_TIME_ENABLED|PERF_FORMAT_TOTAL_TIME_RUNNING;
data->event_attr.disabled = true;
data->initialized = true;
}

static void cgi_pfm_start(cgi_pfm_data *data)
{
if (!data->benchmark) {
return;
}

if (!data->initialized) {
cgi_pfm_initialize(data);
if (!data->benchmark) {
return;
}
}

assert(data->fd == -1);

data->fd = perf_event_open(&data->event_attr, getpid(), -1, -1, 0);
if (data->fd == -1) {
fprintf(stderr, "perf_event_open() failed\n");
fflush(stderr);
cgi_pfm_terminate(data);
return;
}

if (ioctl(data->fd, PERF_EVENT_IOC_ENABLE, 0) != 0) {
fprintf(stderr, "ioctl(PERF_EVENT_IOC_ENABLE) failed\n");
fflush(stderr);
cgi_pfm_terminate(data);
return;
}
}

static void cgi_pfm_end(cgi_pfm_data *data)
{
if (!data->benchmark) {
return;
}

assert(data->initialized);
assert(data->fd != -1);

uint64_t instructions_values[3];
if (ioctl(data->fd, PERF_EVENT_IOC_DISABLE, 0) != 0) {
fprintf(stderr, "ioctl(PERF_EVENT_IOC_DISABLE) failed\n");
fflush(stderr);
pfm_terminate();
return;
}

if (read(data->fd, instructions_values, sizeof(instructions_values)) != sizeof(instructions_values)) {
fprintf(stderr, "read() failed\n");
fflush(stderr);
pfm_terminate();
return;
}

close(data->fd);
data->fd = -1;

if (instructions_values[2]) {
double count = ((double)instructions_values[0] * instructions_values[1] / instructions_values[2]);
data->instructions_sum += count;
data->iterations++;
}
}

static void cgi_pfm_print(cgi_pfm_data *data)
{
if (data->iterations == 0) {
return;
}

uint64_t instructions_mean = (uint64_t)(data->instructions_sum / data->iterations);
fprintf(stderr, "{\"instructions:u\": {\"mean\": %"PRIu64"}}\n", instructions_mean);
fflush(stderr);
}
#endif

static int sapi_cgi_activate(void)
{
/* PATH_TRANSLATED should be defined at this stage but better safe than sorry :) */
Expand Down Expand Up @@ -1749,6 +1874,10 @@ int main(int argc, char *argv[])
char *decoded_query_string;
int skip_getopt = 0;

#ifdef HAVE_PFM
cgi_pfm_data pfm_data = {0};
#endif

#if defined(SIGPIPE) && defined(SIG_IGN)
signal(SIGPIPE, SIG_IGN); /* ignore SIGPIPE in standalone mode so
that sockets created via fsockopen()
Expand Down Expand Up @@ -2211,6 +2340,9 @@ consult the installation file that came with this distribution, or visit \n\
switch (c) {
case 'T':
benchmark = 1;
#ifdef HAVE_PFM
pfm_data.benchmark = true;
#endif
{
char *comma = strchr(php_optarg, ',');
if (comma) {
Expand Down Expand Up @@ -2496,6 +2628,12 @@ consult the installation file that came with this distribution, or visit \n\
CG(skip_shebang) = 1;
}

#ifdef HAVE_PFM
if (!fastcgi && warmup_repeats == 0) {
cgi_pfm_start(&pfm_data);
}
#endif

switch (behavior) {
case PHP_MODE_STANDARD:
php_execute_script(&file_handle);
Expand Down Expand Up @@ -2562,6 +2700,10 @@ consult the installation file that came with this distribution, or visit \n\
}
continue;
} else {
#ifdef HAVE_PFM
cgi_pfm_end(&pfm_data);
#endif

repeats--;
if (repeats > 0) {
script_file = NULL;
Expand Down Expand Up @@ -2621,7 +2763,13 @@ consult the installation file that came with this distribution, or visit \n\
sec = (int)(end - start);
fprintf(stderr, "\nElapsed time: %d sec\n", sec);
#endif
#ifdef HAVE_PFM
if (pfm_data.benchmark) {
cgi_pfm_print(&pfm_data);
cgi_pfm_terminate(&pfm_data);
}
}
#endif

parent_out:

Expand Down
32 changes: 32 additions & 0 deletions sapi/cgi/config9.m4
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,38 @@ PHP_ARG_ENABLE([cgi],,
[yes],
[no])

PHP_ARG_WITH([pfm],
[whether to enable pfm support],
[AS_HELP_STRING([--with-pfm],
[Enable pfm support])],
[no],
[no])

if test "$PHP_PFM" != "no"; then
AC_MSG_CHECKING(for pfm in default path)
for i in /usr/local /usr; do
if test -r $i/include/perfmon/pfmlib.h; then
PFM_DIR=$i
AC_MSG_RESULT(found in $i)
break
fi
done

if test -z "$PFM_DIR"; then
AC_MSG_RESULT(not found)
AC_MSG_ERROR(Please reinstall the pfm distribution)
fi

PHP_CHECK_LIBRARY(pfm, pfm_get_pmu_info,
[
PHP_ADD_INCLUDE($PFM_DIR/include)
PHP_ADD_LIBRARY_WITH_PATH(pfm, $PFM_DIR/$PHP_LIBDIR, PFM_SHARED_LIBADD)
AC_DEFINE(HAVE_PFM,1,[ ])
],
[AC_MSG_ERROR(pfm not found)],
[-L$PFM_DIR/$PHP_LIBDIR])
fi

dnl CGI setup.
AC_MSG_CHECKING(for CGI build)
if test "$PHP_CGI" != "no"; then
Expand Down