Page MenuHomePhabricator

Support macOS compatibility
Closed, ResolvedPublic

Description

It would be nice if one could build php-excimer for macOS. Currently, the error is:

❯ make
/bin/sh /Users/kostajh/src/php-excimer/libtool --mode=compile /usr/bin/gcc  -I. -I/Users/kostajh/src/php-excimer -DPHP_ATOM_INC -I/Users/kostajh/src/php-excimer/include -I/Users/kostajh/src/php-excimer/main -I/Users/kostajh/src/php-excimer -I/opt/homebrew/Cellar/php@7.4/7.4.30/include/php -I/opt/homebrew/Cellar/php@7.4/7.4.30/include/php/main -I/opt/homebrew/Cellar/php@7.4/7.4.30/include/php/TSRM -I/opt/homebrew/Cellar/php@7.4/7.4.30/include/php/Zend -I/opt/homebrew/Cellar/php@7.4/7.4.30/include/php/ext -I/opt/homebrew/Cellar/php@7.4/7.4.30/include/php/ext/date/lib  -DHAVE_CONFIG_H  -g -O2   -c /Users/kostajh/src/php-excimer/excimer.c -o excimer.lo
 /usr/bin/gcc -I. -I/Users/kostajh/src/php-excimer -DPHP_ATOM_INC -I/Users/kostajh/src/php-excimer/include -I/Users/kostajh/src/php-excimer/main -I/Users/kostajh/src/php-excimer -I/opt/homebrew/Cellar/php@7.4/7.4.30/include/php -I/opt/homebrew/Cellar/php@7.4/7.4.30/include/php/main -I/opt/homebrew/Cellar/php@7.4/7.4.30/include/php/TSRM -I/opt/homebrew/Cellar/php@7.4/7.4.30/include/php/Zend -I/opt/homebrew/Cellar/php@7.4/7.4.30/include/php/ext -I/opt/homebrew/Cellar/php@7.4/7.4.30/include/php/ext/date/lib -DHAVE_CONFIG_H -g -O2 -c /Users/kostajh/src/php-excimer/excimer.c  -fno-common -DPIC -o .libs/excimer.o
In file included from /Users/kostajh/src/php-excimer/excimer.c:35:
./excimer_timer.h:52:2: error: unknown type name 'timer_t'; did you mean 'time_t'?
        timer_t timer_id;
        ^~~~~~~
        time_t
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/_types/_time_t.h:31:33: note: 'time_t' declared here
typedef __darwin_time_t         time_t;
                                ^
1 error generated.
make: *** [excimer.lo] Error 1

This page is relevant https://unix.stackexchange.com/questions/194480/why-is-timer-t-defined-in-time-h-on-linux-but-not-os-x

Event Timeline

@tstarling is this something that is relatively easy to do? It would be nice to be able to use Excimer in my local development environment, where I am running PHP on macOS.

There is also T240664 for LuaSandbox which fails with the same error.

I haven't done any work on Mac OS support because, if I understand correctly, it's not easy to set up a VM. If I need to investigate a Windows bug, I can download a VM image straight from Microsoft and use it for free. For Mac OS, maybe it is possible using an unofficial download channel, but it's unclear whether it would be legal to do that. Officially, if you want to fix a bug on a Mac, you're meant to buy a Mac.

I can merge patches for Mac OS if it looks like they won't harm Linux support.

Change 997342 had a related patch set uploaded (by TK-999; author: TK-999):

[mediawiki/php/excimer@master] Implement preliminary macOS support

https://gerrit.wikimedia.org/r/997342

It seems that kqueue is usable on macOS for at least wall-time profiling and simple timers—and unlike other Apple-specific APIs, should be available on other OSes too like BSD, which should facilitate testing. I cobbled together a patch leveraging this that seems to work on macOS.

Change 997342 merged by jenkins-bot:

[mediawiki/php/excimer@master] Implement partial macOS support

https://gerrit.wikimedia.org/r/997342

Change 1004806 had a related patch set uploaded (by Krinkle; author: Krinkle):

[mediawiki/php/excimer@master] Release 1.2.0

https://gerrit.wikimedia.org/r/1004806

Two things stand out to me when testing this locally (Homebrew, PHP 8.2.14).

Firstly, there's a compiler warning:

/Users/krinkle/Development/mediawiki-php-excimer/excimer_log.c:410:58: warning: format specifies type 'long' but the argument has type 'zend_long' (aka 'long long') [-Wformat]
                excimer_log_smart_str_append_printf(&ss_out, " %ld\n", Z_LVAL_P(zp_count));
                                                               ~~~     ^~~~~~~~~~~~~~~~~~
                                                               %lld
/opt/homebrew/Cellar/php@8.2/8.2.14/include/php/Zend/zend_types.h:848:28: note: expanded from macro 'Z_LVAL_P'
#define Z_LVAL_P(zval_p)                        Z_LVAL(*(zval_p))
                                                ^~~~~~~~~~~~~~~~~
/opt/homebrew/Cellar/php@8.2/8.2.14/include/php/Zend/zend_types.h:847:25: note: expanded from macro 'Z_LVAL'
#define Z_LVAL(zval)                            (zval).value.lval
                                                ^~~~~~~~~~~~~~~~~
1 warning generated.

Secondly, when serving MediaWiki (composer serve), every page view fatals immediately upon the first attempt to connection to the database (i.e. sqlite, though doesn't seem specific to sqlite).

Original exception:
   [f643e60c3908e8a2a232f22f] /index.php/Main_Page Wikimedia\RequestTimeout\EmergencyTimeoutException:
   The critical section "Database::executeQuery" timed out after 180 seconds
Backtrace:
from mediawiki/vendor/wikimedia/request-timeout/src/Detail/CriticalSection.php(31)
#0 mediawiki/includes/AutoLoader.php(189):
   Wikimedia\RequestTimeout\Detail\CriticalSection::Wikimedia\RequestTimeout\Detail\{closure}(integer)
#1 AutoLoader::find(string)
#2 AutoLoader::autoload(string)
#3 Wikimedia\RequestTimeout\CriticalSectionProvider->scopedEnter(string, NULL, NULL, Closure)
#4 Database->commenceCriticalSection(string)
#5 Database->executeQuery(Query, string, integer)
#6 Database->query(Query, string)
#7 DatabaseSqlite->open(NULL, NULL, string, string, NULL, string)
#8 Database->initConnection()
#9 LoadBalancer->reallyOpenConnection(integer, DatabaseDomain, array)
#10 LoadBalancer->reuseOrOpenConnectionForNewRef(integer, DatabaseDomain, integer)
#11 LoadBalancer->getServerConnection(integer, string, integer)
#12 LoadBalancer->getConnectionInternal(integer, array, string, integer)
#13 DBConnRef->ensureConnection()
#14 DBConnRef->__call(string, array)
…
#31 MediaWiki\Actions\ActionEntryPoint->performRequest()
#32 MediaWiki\Actions\ActionEntryPoint->execute()
#33 MediaWiki\MediaWikiEntryPoint->run()
#34 {main}

It seems this critical timer is preceiving a timeout as soon as the timer starts (as opposed to after 180 seconds have passed).

In vendor/wikimedia/request-timeout/src/RequestTimeout.php#factory this can be temporarily disabled by forcing the extension_loaded( 'excimer' ) conditional to false. Once done, MediaWiki generally works, including to use php-excimer as sampling profiler with snippets like https://www.mediawiki.org/wiki/Excimer#Per-process_flame_graph_(Speedscope) and https://www.mediawiki.org/wiki/MediaWiki-Docker/Configuration_recipes/Profiling#Flame_graph.

In vendor/wikimedia/request-timeout, ExcimerTimerWrapper is described as using a wall-clock timer, powered with ExcimerTimer, which in turn is documented as defaulting to EXCIMER_REAL.

I'm guessing either:

  • wikimedia/request-timeout is excercising a bug in the new excimer_os_timer_kqueue.c file that profiling doesn't expose (seems unlikely given one-off timer is a subset of profiling, mostly)
  • excimer_os_timer_kqueue.c is ignoring the given interval or interpreting it as way shorter than it should be, which is hard to notice during profiling.

Change 1005099 had a related patch set uploaded (by TK-999; author: TK-999):

[mediawiki/php/excimer@master] Fix setInterval() handling with the kqueue backend

https://gerrit.wikimedia.org/r/1005099

Change 1005099 merged by jenkins-bot:

[mediawiki/php/excimer@master] Fix setInterval() handling with the kqueue backend

https://gerrit.wikimedia.org/r/1005099

Two things stand out to me when testing this locally (Homebrew, PHP 8.2.14).

We should document how to set this up on macOS. What would be the best place? A new section of https://www.mediawiki.org/wiki/Excimer#Per-process_flame_graph_(Speedscope)? (cc @apaskulin)

I'm assuming/hoping that after the next release, pecl install excimer will work for macOS, the way it already does for e.g. php-apcu, php-xdebug and other native PHP extensions. Perhaps I'm missing a reason why it wouldn't. We'll find out after the next release I suppose.

I'm assuming/hoping that after the next release, pecl install excimer will work for macOS, the way it already does for e.g. php-apcu, php-xdebug and other native PHP extensions. Perhaps I'm missing a reason why it wouldn't. We'll find out after the next release I suppose.

Ah, I hadn't realized that excimer was available via pecl. Cool!

Change 1004806 merged by jenkins-bot:

[mediawiki/php/excimer@master] Release 1.2.0

https://gerrit.wikimedia.org/r/1004806

Krinkle assigned this task to TK-999.
Krinkle triaged this task as Medium priority.