Skip to content
This repository has been archived by the owner on Jan 13, 2022. It is now read-only.

Commit

Permalink
Add Memcached support for the MediaWiki target
Browse files Browse the repository at this point in the history
This diff adds support for Memcached. If a target supports Memcached,
oss-performance will start it on 127.0.0.1:11888. The only target supporting
Memcached right now is MediaWiki. For other targets to support Memcached, they
must override PerfTarget::supportsMemcached().
This diff also sets $wgUseDatabaseMessages to false in the configuration file
if Memcached is disabled, as recommended in the MediaWiki manual.

For MediaWiki with Memcached enabled, observing a ~6% increase in RPS, a
decrease in system idle time, as well as ~7 percentage points more cycles being
spent in HHVM.

Command line options added:

--memcached: path to memcached binary
--delay-memcached-startup: number of seconds to delay Memcached startup
--memcached-port: TCP port to listen on (default is 11888)
--no-memcached: don't use memcached (even if target supports it)
--memcached-threads: number of memcached threads to spawn (default is 4 for
machines with small number of cores, 32 otherwise)
  • Loading branch information
octmoraru committed Sep 19, 2017
1 parent e783511 commit 4e07eb9
Show file tree
Hide file tree
Showing 8 changed files with 145 additions and 8 deletions.
75 changes: 75 additions & 0 deletions base/MemcachedDaemon.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<?hh
/*
* Copyright (c) 2017, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
final class MemcachedDaemon extends Process {

private int $maxMemory = 2048;

public function __construct(
private PerfOptions $options,
private PerfTarget $target,
) {
parent::__construct($this->options->memcached);
}

public function start(): void {
parent::startWorker(
$this->options->daemonOutputFileName('memcached'),
$this->options->delayProcessLaunch,
$this->options->traceSubProcess,
);
}

public function getNumThreads(): int {
$output = [];
$ret = -1;
if ($this->options->memcachedThreads != 0) {
return $this->options->memcachedThreads;
}

exec('nproc', $output, $ret);
if ($ret != 0) {
invariant_violation('%s', 'Execution of nproc failed');
exit(1);
}
$numProcs = (int)($output[0]);

// for small number of cores, use the default, which is 4;
// otherwise, we probably need more
if ($numProcs <= 8)
return 4;

return 32;
}

<<__Override>>
protected function getPidFilePath(): string {
return $this->options->tempDir.'/memcached.pid';
}

<<__Override>>
protected function getArguments(): Vector<string> {
if ($this->options->cpuBind) {
$this->cpuRange = $this->options->helperProcessors;
}
return Vector {
'-m',
(string) $this->maxMemory,
'-l',
'127.0.0.1',
'-t',
(string) $this->getNumThreads(),
'-p',
(string) $this->options->memcachedPort,
'-P', # pid file
$this->getPidFilePath()
};
}
}
18 changes: 17 additions & 1 deletion base/PerfOptions.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ final class PerfOptions {

public string $siege;
public string $nginx;
public string $memcached;

public ?string $dbUsername;
public ?string $dbPassword;
Expand Down Expand Up @@ -87,6 +88,8 @@ final class PerfOptions {

public bool $applyPatches = false;

public bool $useMemcached = true;

//
// All times are given in seconds, stored in a float.
// For PHP code, the usleep timer is used, so fractional seconds work fine.
Expand All @@ -97,6 +100,7 @@ final class PerfOptions {
//
public float $delayNginxStartup;
public float $delayPhpStartup;
public float $delayMemcachedStartup;
public float $delayProcessLaunch; // secs to wait after start process
public float $delayCheckHealth; // secs to wait before hit /check-health

Expand All @@ -123,6 +127,8 @@ final class PerfOptions {
public bool $notBenchmarking = false;

public string $dbHost = '127.0.0.1'; //The hostname/IP of server which hosts the database.
public int $memcachedPort; //The hostname/IP of server which hosts memcached.
public int $memcachedThreads; // Number of memcached threads

private array $args;
private Vector<string> $notBenchmarkingArgs = Vector {};
Expand All @@ -140,6 +146,7 @@ public function __construct(Vector<string> $argv) {
'no-fpm',
'siege:',
'nginx:',
'memcached:',
'wait-at-end',
'wait-after-warmup',
'no-proxygen',
Expand Down Expand Up @@ -176,6 +183,7 @@ public function __construct(Vector<string> $argv) {
'trace',
'delay-nginx-startup:',
'delay-php-startup:',
'delay-memcached-startup:',
'delay-process-launch:',
'delay-check-health:',
'max-delay-unfreeze:',
Expand All @@ -192,6 +200,9 @@ public function __construct(Vector<string> $argv) {
'server-threads:',
'client-threads:',
'remote-siege:',
'memcached-port:',
'memcached-threads:',
'no-memcached', // do not use memcached (even if target supports it)
};
$targets = $this->getTargetDefinitions()->keys();
$def->addAll($targets);
Expand Down Expand Up @@ -238,6 +249,9 @@ public function __construct(Vector<string> $argv) {

$this->siege = hphp_array_idx($o, 'siege', 'siege');
$this->nginx = hphp_array_idx($o, 'nginx', 'nginx');
$this->memcached = hphp_array_idx($o, 'memcached', 'memcached');
$this->memcachedPort = (int) hphp_array_idx($o, 'memcached-port', 11888);
$this->memcachedThreads = (int) hphp_array_idx($o, 'memcached-threads', 0);

$isFacebook = array_key_exists('fbcode', $o);
$fbcode = "";
Expand Down Expand Up @@ -276,6 +290,7 @@ public function __construct(Vector<string> $argv) {
$this->statCache = $this->getBool('stat-cache');
$this->jit = !$this->getBool('no-jit');
$this->applyPatches = $this->getBool('apply-patches');
$this->useMemcached = !$this->getBool('no-memcached');

$fraction = $this->getFloat('cpu-fraction', 1.0);
if ($fraction !== 1.0) {
Expand Down Expand Up @@ -318,6 +333,7 @@ public function __construct(Vector<string> $argv) {
$this->phpFCGIChildren = $this->getInt('php-fcgi-children', 100);
$this->delayNginxStartup = $this->getFloat('delay-nginx-startup', 0.1);
$this->delayPhpStartup = $this->getFloat('delay-php-startup', 1.0);
$this->delayMemcachedStartup = $this->getFloat('delay-memcached-startup', 1.0);
$this->delayProcessLaunch = $this->getFloat('delay-process-launch', 0.0);
$this->delayCheckHealth = $this->getFloat('delay-check-health', 1.0);
$this->maxdelayUnfreeze = $this->getFloat('max-delay-unfreeze', 60.0);
Expand All @@ -344,7 +360,7 @@ public function __construct(Vector<string> $argv) {
if (array_key_exists('client-threads', $o)) {
$this->clientThreads = $this->args['client-threads'];
}

if ($argTempDir === null) {
$this->tempDir = tempnam('/tmp', 'hhvm-nginx');
// Currently a file - change to a dir
Expand Down
7 changes: 7 additions & 0 deletions base/PerfRunner.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,13 @@ private static function RunWithOptionsAndEngine(
Process::sleepSeconds($options->delayNginxStartup);
invariant($nginx->isRunning(), 'Failed to start nginx');

if ($options->useMemcached && $target->supportsMemcached()) {
self::PrintProgress('Starting Memcached');
$memcached = new MemcachedDaemon($options, $target);
Process::sleepSeconds($options->delayMemcachedStartup);
$memcached->start();
}

self::PrintProgress('Starting PHP Engine');
$php_engine->start();
Process::sleepSeconds($options->delayPhpStartup);
Expand Down
4 changes: 4 additions & 0 deletions base/PerfTarget.php
Original file line number Diff line number Diff line change
Expand Up @@ -111,4 +111,8 @@ public function __toString(): string {
public function getSiegeRCPath(): ?string {
return null;
}

public function supportsMemcached(): bool {
return false;
}
}
9 changes: 7 additions & 2 deletions base/SystemChecks.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
class SystemChecks {
public static function CheckAll(PerfOptions $options): void {
self::CheckNotRoot();
self::CheckPortAvailability();
self::CheckPortAvailability($options);
self::CheckCPUFreq();
self::CheckTCPTimeWaitReuse();
self::CheckForAuditd($options);
Expand Down Expand Up @@ -71,13 +71,18 @@ private static function CheckCPUFreq(): void {
}
}

private static function CheckPortAvailability(): void {
private static function CheckPortAvailability(PerfOptions $options): void {
$ports = Vector {
PerfSettings::HttpPort(),
PerfSettings::HttpAdminPort(),
PerfSettings::BackendPort(),
PerfSettings::BackendAdminPort(),
};
if ($options->useMemcached &&
$options->getTarget()->supportsMemcached()) {
$ports[] = $options->memcachedPort;
}

$busy_ports = Vector {};
foreach ($ports as $port) {
$result = @fsockopen('localhost', $port);
Expand Down
3 changes: 3 additions & 0 deletions targets/mediawiki/LocalSettings.php
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,9 @@
require_once "$IP/extensions/TitleBlacklist/TitleBlacklist.php";
require_once "$IP/extensions/WikiEditor/WikiEditor.php";

# This option should be false if we are not using memcached, otherwise it will incur a significant performance penalty
# source: https://www.mediawiki.org/wiki/Manual:$wgUseDatabaseMessages
$wgUseDatabaseMessages = false;

# End of automatically generated settings.
# Add more configuration options below.
29 changes: 24 additions & 5 deletions targets/mediawiki/MediaWikiTarget.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ protected function getSanityCheckString(): string {
return 'Obama';
}

private function replaceInFile(string $fileName, string $search, string $replace) {
$file = $this->getSourceRoot().'/'.$fileName;
$file_contents = file_get_contents($file);
$file_contents = str_replace($search, $replace, $file_contents);
file_put_contents($file, $file_contents);
}

public function install(): void {
$src_dir = $this->options->srcDir;
if ($src_dir) {
Expand All @@ -41,16 +48,23 @@ public function install(): void {
mkdir($cache_dir);
copy(__DIR__.'/LocalSettings.php', $this->getSourceRoot().'/LocalSettings.php');

$file = $this->getSourceRoot().'/LocalSettings.php';
$file_contents = file_get_contents($file);
$file_contents = str_replace('__DB_HOST__', $this->options->dbHost, $file_contents );
file_put_contents($file, $file_contents);
$this->replaceInFile('LocalSettings.php', '__DB_HOST__', $this->options->dbHost);

file_put_contents(
$this->getSourceRoot().'/LocalSettings.php',
'$wgCacheDirectory="'.$cache_dir.'";',
'$wgCacheDirectory="'.$cache_dir.'";'."\n",
FILE_APPEND,
);
if ($this->options->useMemcached) {
copy(__DIR__.'/Memcached.php', $this->getSourceRoot().'/Memcached.php');
$this->replaceInFile('Memcached.php', '__MEMCACHED_HOST__', '127.0.0.1');
$this->replaceInFile('Memcached.php', '__MEMCACHED_PORT__', (string) $this->options->memcachedPort);
file_put_contents(
$this->getSourceRoot().'/LocalSettings.php',
'require_once "'.$this->getSourceRoot().'/Memcached.php";'."\n",
FILE_APPEND,
);
}
}

<<__Override>>
Expand All @@ -67,4 +81,9 @@ public function postInstall(): void {
public function getSourceRoot(): string {
return $this->options->tempDir.'/'.self::MEDIAWIKI_VERSION;
}

<<__Override>>
public function supportsMemcached(): bool {
return true;
}
}
8 changes: 8 additions & 0 deletions targets/mediawiki/Memcached.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

$wgMainCacheType = CACHE_MEMCACHED;
$wgMemCachedServers = array( "__MEMCACHED_HOST__:__MEMCACHED_PORT__" );

$wgSessionCacheType = CACHE_MEMCACHED;
# Turn this option back on if we use memcached
$wgUseDatabaseMessages = true;

0 comments on commit 4e07eb9

Please sign in to comment.