Skip to content

Commit

Permalink
[Perf/HPHPi] optimize constant lookup
Browse files Browse the repository at this point in the history
Summary:
HPHPi constant look up was slow, I made changes to speed up that by
(1) detecting builtin constant at parse time
(2) add findUserConstant without looking up the builtin constant table further
(3) changed m_constant to StringData and use StaticString to speed up the
lookup/comparison

Test Plan:
make fast_tests
make slow_tests
micro benchmark:
<?php
define('FOO', 1);
function foo() {
  $sum = 0;
  for ($i = 1; $i < 50000000; $i++) {
    $sum += FOO;
  }
  return $sum;
}
var_dump(foo());
Before:
real    0m19.038s
user    0m18.980s
sys     0m0.048s
After:
real    0m9.002s
user    0m8.973s
sys     0m0.037s

Reviewed By: stephentu
Reviewers: mwilliams, qigao, stephentu
CC: hphp-diffs@lists, ps, mwilliams, stephentu
Revert Plan:
Tags:

- begin *PUBLIC* platform impact section -
Bugzilla: #
- end platform impact -

Differential Revision: 307167
  • Loading branch information
myang authored and macvicar committed Aug 19, 2011
1 parent 2df1ef6 commit 1a09996
Show file tree
Hide file tree
Showing 8 changed files with 83 additions and 12 deletions.
15 changes: 15 additions & 0 deletions src/compiler/analysis/analysis_result.cpp
Expand Up @@ -3209,6 +3209,20 @@ void AnalysisResult::outputCPPHashTableGetConstant(
" return NULL;\n"
"}\n";

const char text3[] =
"ConstantType check_constant(CStrRef name) {\n"
" const char *s = name.data();\n"
" const hashNodeCon *p = findCon(s, name->hash());\n"
" if (!p) return NoneBuiltinConstant;\n"
" if (p->off > 0) return DynamicBuiltinConstant;\n"
" if (strcmp(s, \"STDIN\") == 0 ||\n"
" strcmp(s, \"STDOUT\") == 0 ||\n"
" strcmp(s, \"STDERR\") == 0) {\n"
" return StdioBuiltinConstant;\n"
" }\n"
" return StaticBuiltinConstant;\n"
"}\n";

int tableSize = Util::roundUpToPowerOfTwo(constMap.size() * 2);
cg_printf(text1,
Type::KindOfBoolean,
Expand Down Expand Up @@ -3277,6 +3291,7 @@ void AnalysisResult::outputCPPHashTableGetConstant(
}
}
cg_printf(text2, tableSize - 1, tableSize - 1);
if (system) cg_printf(text3);
}

void AnalysisResult::outputCPPDynamicConstantTable(
Expand Down
2 changes: 2 additions & 0 deletions src/hphp/externals.cpp
Expand Up @@ -15,6 +15,7 @@
*/

#include <runtime/base/complex_types.h>
#include <runtime/base/externals.h>

using namespace std;

Expand Down Expand Up @@ -59,6 +60,7 @@ Variant invoke_file(CStrRef path, bool once /* = false */,

Variant get_constant(CStrRef name, bool error) { return name;}
Variant get_builtin_constant(CStrRef name, bool error) { return name;}
ConstantType check_constant(CStrRef name) { return NoneBuiltinConstant;}
Variant get_class_constant(CStrRef s, const char *prop,
bool fatal /* = true */) {
return null;
Expand Down
7 changes: 7 additions & 0 deletions src/runtime/base/externals.h
Expand Up @@ -74,6 +74,13 @@ extern Variant get_builtin_class_var_init(CStrRef s, const char *var);
*/
extern Variant get_constant(CStrRef name, bool error = true);
extern Variant get_builtin_constant(CStrRef name, bool error = true);
enum ConstantType {
StaticBuiltinConstant = 0,
StdioBuiltinConstant,
DynamicBuiltinConstant,
NoneBuiltinConstant,
};
extern ConstantType check_constant(CStrRef name);

/**
* Getting a class constant
Expand Down
41 changes: 31 additions & 10 deletions src/runtime/eval/ast/constant_expression.cpp
Expand Up @@ -18,6 +18,7 @@
#include <runtime/base/externals.h>
#include <runtime/ext/ext_misc.h>
#include <runtime/eval/runtime/eval_state.h>
#include <runtime/eval/ast/name.h>

namespace HPHP {
namespace Eval {
Expand All @@ -27,18 +28,38 @@ using namespace std;
ConstantExpression::ConstantExpression(EXPRESSION_ARGS,
const string &constant)
: Expression(KindOfConstantExpression, EXPRESSION_PASS),
m_constant(constant) {}
m_constant(StringName::GetStaticName(constant)) {
m_type = check_constant(m_constant);
if (m_type == StaticBuiltinConstant) {
m_value = get_builtin_constant(m_constant);
}
}

Variant ConstantExpression::eval(VariableEnvironment &env) const {
if (m_constant[0] == '\\') {
Variant ret;
if (RequestEvalState::findConstant(m_constant.c_str() + 1, ret)) {
return ret;
}
int pos = m_constant.rfind('\\');
return get_constant(m_constant.c_str() + pos + 1);
switch (m_type) {
case StaticBuiltinConstant:
return m_value;
case StdioBuiltinConstant:
case DynamicBuiltinConstant:
return get_builtin_constant(m_constant);
case NoneBuiltinConstant:
break;
default:
assert(false);
break;
}
const char *s = m_constant->data();
if (LIKELY(s[0] != '\\')) {
return RequestEvalState::findUserConstant(m_constant);
}
Variant ret;
if (RequestEvalState::findConstant(s + 1, ret)) {
return ret;
}
return get_constant(m_constant);
const char *r = s + m_constant->size() - 1;
while (*r != '\\') r--;
ASSERT(*r == '\\');
return get_constant(r + 1);
}

bool ConstantExpression::evalStaticScalar(VariableEnvironment &env,
Expand All @@ -51,7 +72,7 @@ bool ConstantExpression::evalStaticScalar(VariableEnvironment &env,
}

void ConstantExpression::dump(std::ostream &out) const {
out << m_constant;
out << m_constant->data();
}

///////////////////////////////////////////////////////////////////////////////
Expand Down
6 changes: 4 additions & 2 deletions src/runtime/eval/ast/constant_expression.h
Expand Up @@ -31,9 +31,11 @@ class ConstantExpression : public Expression {
virtual Variant eval(VariableEnvironment &env) const;
virtual bool evalStaticScalar(VariableEnvironment &env, Variant &r) const;
virtual void dump(std::ostream &out) const;
const std::string &getName() const { return m_constant; }
StringData *getName() const { return m_constant; }
private:
std::string m_constant;
StringData *m_constant;
ConstantType m_type;
Variant m_value; // for StaticBuiltinConstant
};

///////////////////////////////////////////////////////////////////////////////
Expand Down
11 changes: 11 additions & 0 deletions src/runtime/eval/runtime/eval_state.cpp
Expand Up @@ -335,6 +335,17 @@ bool RequestEvalState::findConstant(CStrRef name, Variant &ret) {
return false;
}

Variant RequestEvalState::findUserConstant(
CStrRef name, bool error /* = true */) {
RequestEvalState *self = s_res.get();
if (self->m_constants.exists(name)) {
return self->m_constants.rvalAt(name);
}
const char *s = name.c_str();
if (error) raise_notice("Use of undefined constant %s - assumed '%s'", s, s);
return name;
}

bool RequestEvalState::includeFile(Variant &res, CStrRef path, bool once,
LVariableTable* variables,
const char *currentDir) {
Expand Down
1 change: 1 addition & 0 deletions src/runtime/eval/runtime/eval_state.h
Expand Up @@ -151,6 +151,7 @@ class RequestEvalState {
static const FunctionStatement *findUserFunction(CStrRef name);
static const Function *findFunction(CStrRef name);
static bool findConstant(CStrRef name, Variant &ret);
static Variant findUserConstant(CStrRef name, bool error = true);
static bool includeFile(Variant &res, CStrRef path, bool once,
LVariableTable* variables,
const char *currentDir);
Expand Down
12 changes: 12 additions & 0 deletions src/system/gen/sys/dynamic_table_constant.cpp
Expand Up @@ -4226,6 +4226,18 @@ findCon(const char *name, int64 hash) {
}
return NULL;
}
ConstantType check_constant(CStrRef name) {
const char *s = name.data();
const hashNodeCon *p = findCon(s, name->hash());
if (!p) return NoneBuiltinConstant;
if (p->off > 0) return DynamicBuiltinConstant;
if (strcmp(s, "STDIN") == 0 ||
strcmp(s, "STDOUT") == 0 ||
strcmp(s, "STDERR") == 0) {
return StdioBuiltinConstant;
}
return StaticBuiltinConstant;
}
Variant get_builtin_constant(CStrRef name, bool error) {
DECLARE_SYSTEM_GLOBALS(g);
const char* s = name.data();
Expand Down

0 comments on commit 1a09996

Please sign in to comment.