Use makePseudoMainExit in more places
[hiphop-php.git] / hphp / runtime / vm / runtime-type-profiler.cpp
blob555f54dd37d1b83fdaa39380ac724e5177074e92
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2014 Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
18 #include "hphp/runtime/vm/runtime-type-profiler.h"
20 #include <iostream>
21 #include <fstream>
22 #include <sstream>
23 #include <string.h>
24 #include <stdio.h>
26 #include "folly/AtomicHashMap.h"
27 #include "folly/dynamic.h"
28 #include "folly/json.h"
30 #include "hphp/runtime/base/type-array.h"
31 #include "hphp/runtime/base/type-string.h"
32 #include "hphp/util/atomic-vector.h"
34 namespace HPHP {
36 //////////////////////////////////////////////////////////////////////
39 * Holds an atomic count of profiled types.
41 namespace {
42 struct ProfileCounter {
43 std::atomic<int64_t> m_count;
45 ProfileCounter() : m_count(0) {}
46 ~ProfileCounter() = default;
47 ProfileCounter& operator=(const ProfileCounter& pc) = delete;
49 ProfileCounter(const ProfileCounter& pc) : m_count(pc.m_count.load()) {}
50 void inc() { m_count.fetch_add(1); }
51 int64_t load() { return m_count.load(); }
55 typedef folly::AtomicHashMap<const char*,ProfileCounter,cstr_hash,eqstr>
56 TypeCounter;
57 typedef AtomicVector<TypeCounter*> FuncTypeCounter;
58 typedef AtomicVector<FuncTypeCounter*> RuntimeProfileInfo;
60 //////////////////////////////////////////////////////////////////////
62 static const int kShowTopN = 6;
64 static FuncTypeCounter emptyFuncCounter(1,0);
65 static RuntimeProfileInfo* allProfileInfo;
66 static std::atomic<int> counter(0);
68 //////////////////////////////////////////////////////////////////////
70 namespace {
72 void initFuncTypeProfileData(const Func* func) {
73 auto myVector = new FuncTypeCounter(func->numParams() + 1, 0);
74 for (long i = 0; i < func->numParams() + 1; i++) {
75 myVector->exchange(i, new TypeCounter(200));
77 allProfileInfo->exchange(func->getFuncId(), myVector);
80 const char* getTypeString(const TypedValue* value) {
81 if (value->m_type == KindOfObject) {
82 return value->m_data.pobj->o_getClassName().data();
84 if (value->m_type == KindOfResource) {
85 return value->m_data.pres->o_getClassName().data();
87 return getDataTypeString(value->m_type).c_str();
90 void logType(const Func* func, int32_t paramIndex, const char* typeString) {
91 if (paramIndex > func->numParams()) {
92 // Don't bother logging types for extra args.
93 return;
95 if (allProfileInfo->get(func->getFuncId()) == &emptyFuncCounter) {
96 initFuncTypeProfileData(func);
98 auto it = allProfileInfo->get(func->getFuncId());
99 TypeCounter* hashmap = it->get(paramIndex);
100 try {
101 auto result = hashmap->insert(typeString, ProfileCounter());
102 result.first->second.inc();
103 } catch (folly::AtomicHashMapFullError& e) {
104 // Fail silently if hashmap is full
108 Array getTopN(Array &allTypes, int n) {
109 Array ret;
110 for (int i = 0; i < n; i ++ ) {
111 double max = 0;
112 String max_key;
113 for (ArrayIter iter(allTypes); iter; ++iter) {
114 if (iter.second().toDouble() > max) {
115 max_key = iter.first().toString();
116 max = iter.second().toDouble();
119 if (max != 0) {
120 ret.set(max_key, VarNR(max));
121 allTypes.remove(max_key);
124 return ret;
129 //////////////////////////////////////////////////////////////////////
131 void initTypeProfileStructure() {
132 allProfileInfo = new RuntimeProfileInfo(750000, &emptyFuncCounter);
135 void profileOneArgument(const TypedValue value, const int32_t paramIndex,
136 const Func* func) {
137 assert(allProfileInfo != nullptr);
138 if (!func || !func->fullName()) return;
140 const char* typeString = getTypeString(&value);
142 if (func->fullName()->size() != 0) {
143 logType(func, paramIndex + 1, typeString);
146 if (paramIndex == -1) {
147 counter++;
150 if (RuntimeOption::EvalRuntimeTypeProfileLoggingFreq &&
151 counter.load() % RuntimeOption::EvalRuntimeTypeProfileLoggingFreq == 0) {
152 writeProfileInformationToDisk();
156 void profileAllArguments(ActRec* ar) {
157 for (int i = 0; i < ar->m_func->numParams(); i++) {
158 logType(ar->m_func, i + 1, getTypeString(frame_local(ar, i)));
162 Array getPercentParamInfoArray(const Func* func) {
163 Array ret;
164 auto funcParamMap = allProfileInfo->get(func->getFuncId());
165 for (int i = 0; i <= func->numParams(); i++) {
166 Array types;
167 auto typeCount = funcParamMap->get(i);
168 if (typeCount == nullptr) {
169 break;
171 int64_t total = 0;
172 for (auto j = typeCount->begin(); j != typeCount->end(); j++) {
173 total += j->second.load();
175 for (auto j = typeCount->begin(); j != typeCount->end(); j++) {
176 String key = String(j->first);
177 int64_t count = j->second.load();
178 types.set(key, VarNR(double(count) / total));
180 Array topTypes = getTopN(types, kShowTopN);
181 ret.append(VarNR(topTypes));
183 return ret;
186 void writeProfileInformationToDisk() {
187 assert(allProfileInfo != nullptr);
188 folly::dynamic all_info = folly::dynamic::object;
189 for (auto i = 0; i <= Func::nextFuncId(); i++) {
190 folly::dynamic info = {};
191 auto funcParamMap = allProfileInfo->get(i);
192 if (funcParamMap == &emptyFuncCounter) {
193 continue;
195 for (auto j = 0; j <= Func::fromFuncId(i)->numParams(); j++) {
196 auto typeCount = funcParamMap->get(j);
197 if (typeCount == nullptr) {
198 continue;
200 info.push_back(folly::dynamic::object);
201 for (auto k = typeCount->begin(); k != typeCount->end(); k++) {
202 folly::dynamic key = std::string(k->first);
203 folly::dynamic value = k->second.load();
204 info[j][key] = value;
207 const Func* func = Func::fromFuncId(i);
208 all_info[std::string(func->fullName()->data())] = info;
210 std::ofstream logfile;
211 logfile.open("/tmp/type-profile.txt", std::fstream::out | std::fstream::app);
212 logfile << folly::toJson(all_info).toStdString();
213 logfile.close();