BeefPerf.cpp 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815
  1. #ifndef NOMINMAX
  2. #define NOMINMAX
  3. #endif
  4. #include "BeefPerf.h"
  5. #include "platform/PlatformHelper.h"
  6. #ifndef BP_DISABLED
  7. #ifndef BF_PLATFORM_WINDOWS
  8. #include <netinet/in.h>
  9. #include <netinet/ip.h>
  10. #include <sys/ioctl.h>
  11. #include <sys/types.h>
  12. #include <netdb.h>
  13. typedef fd_set FD_SET;
  14. #define closesocket close
  15. #endif
  16. #ifdef BF_PLATFORM_MACOS
  17. #include <sys/socket.h>
  18. #include <mach/error.h>
  19. #include <mach/mach.h>
  20. #endif
  21. #ifdef BF_PLATFORM_POSIX
  22. #include <cerrno>
  23. #endif
  24. #pragma comment(lib,"wsock32.lib")
  25. #pragma warning(disable:4996)
  26. USING_NS_BF;
  27. // All DLLs must use the same ABI version
  28. #define BP_ABI_VERSION 3
  29. BpManager* BpManager::sBpManager = NULL;
  30. static bool gOwnsBpManager = false;
  31. static BpThreadInfo sFakeThreadInfo;
  32. struct BpManagerOwner
  33. {
  34. BpManager* mOwnedManager;
  35. bool mDidShutdown;
  36. BpManagerOwner()
  37. {
  38. mOwnedManager = NULL;
  39. mDidShutdown = false;
  40. }
  41. ~BpManagerOwner()
  42. {
  43. mDidShutdown = true;
  44. delete mOwnedManager;
  45. }
  46. };
  47. static BpManagerOwner gBpManagerOwner;
  48. BF_TLS_DECLSPEC BpThreadInfo* Beefy::BpManager::sBpThreadInfo;
  49. inline void EncodeSLEB128(uint8*& buf, int value)
  50. {
  51. bool hasMore;
  52. do
  53. {
  54. uint8 curByte = (uint8)(value & 0x7f);
  55. value >>= 7;
  56. hasMore = !((((value == 0) && ((curByte & 0x40) == 0)) ||
  57. ((value == -1) && ((curByte & 0x40) != 0))));
  58. if (hasMore)
  59. curByte |= 0x80;
  60. *(buf++) = curByte;
  61. }
  62. while (hasMore);
  63. }
  64. inline void EncodeSLEB128(uint8*& buf, int64_t value)
  65. {
  66. bool hasMore;
  67. do
  68. {
  69. uint8 curByte = (uint8)(value & 0x7f);
  70. value >>= 7;
  71. hasMore = !((((value == 0) && ((curByte & 0x40) == 0)) ||
  72. ((value == -1) && ((curByte & 0x40) != 0))));
  73. if (hasMore)
  74. curByte |= 0x80;
  75. *(buf++) = curByte;
  76. }
  77. while (hasMore);
  78. }
  79. inline void EncodeULEB32(uint8*& buf, uint64 value)
  80. {
  81. do
  82. {
  83. uint8 byteVal = value & 0x1f;
  84. value >>= 5;
  85. if (value != 0)
  86. byteVal |= 0x20; // Mark this byte to show that more bytes will follow
  87. *(buf++) = byteVal;
  88. }
  89. while (value != 0);
  90. }
  91. //////////////////////////////////////////////////////////////////////////
  92. Buffer::Buffer()
  93. {
  94. mPtr = NULL;
  95. mBufSize = 0;
  96. mDataSize = 0;
  97. }
  98. Buffer::~Buffer()
  99. {
  100. delete mPtr;
  101. }
  102. uint8* Buffer::Alloc(int size)
  103. {
  104. if (mDataSize + size > mBufSize)
  105. {
  106. // Grow factor 50%
  107. int wantSize = max(mDataSize + size, mBufSize + mBufSize / 2);
  108. auto bpManager = BpManager::Get();
  109. //uint8* newPtr = new uint8[wantSize];
  110. uint8* newPtr = (uint8*)bpManager->AllocBytes(wantSize);
  111. memcpy(newPtr, mPtr, mDataSize);
  112. //delete mPtr;
  113. bpManager->FreeBytes(mPtr);
  114. mPtr = newPtr;
  115. mBufSize = wantSize;
  116. }
  117. uint8* ptr = mPtr + mDataSize;
  118. mDataSize += size;
  119. return ptr;
  120. }
  121. void Buffer::Free()
  122. {
  123. //delete mPtr;
  124. BpManager::Get()->FreeBytes(mPtr);
  125. mPtr = NULL;
  126. mDataSize = 0;
  127. mBufSize = 0;
  128. }
  129. void Buffer::Clear()
  130. {
  131. mDataSize = 0;
  132. }
  133. //////////////////////////////////////////////////////////////////////////
  134. CircularBuffer::View::View()
  135. {
  136. mPtr = NULL;
  137. mCircularBuffer = NULL;
  138. mTempBuf = NULL;
  139. mTempBufSize = 0;
  140. mSrcIdx = 0;
  141. mSrcSize = 0;
  142. }
  143. CircularBuffer::View::~View()
  144. {
  145. delete mTempBuf;
  146. }
  147. void CircularBuffer::View::Commit(int size)
  148. {
  149. if (mPtr == mTempBuf)
  150. {
  151. if (size == -1)
  152. size = mSrcSize;
  153. else
  154. BF_ASSERT(size <= mSrcSize);
  155. mCircularBuffer->Write(mTempBuf, mSrcIdx, size);
  156. }
  157. else if (size != -1)
  158. BF_ASSERT(size <= mSrcSize);
  159. }
  160. CircularBuffer::CircularBuffer()
  161. {
  162. mTail = 0;
  163. mBufSize = 0;
  164. mDataSize = 0;
  165. mBuffer = NULL;
  166. }
  167. CircularBuffer::~CircularBuffer()
  168. {
  169. delete mBuffer;
  170. }
  171. void CircularBuffer::Clear()
  172. {
  173. mTail = 0;
  174. mDataSize = 0;
  175. }
  176. void CircularBuffer::Resize(int newSize)
  177. {
  178. uint8* newBuffer = new uint8[newSize];
  179. Read(newBuffer, 0, mDataSize);
  180. delete mBuffer;
  181. mBuffer = newBuffer;
  182. mBufSize = newSize;
  183. mTail = 0;
  184. }
  185. void CircularBuffer::GrowReserve(int addSize)
  186. {
  187. if (mDataSize + addSize <= mBufSize)
  188. return;
  189. Resize(max(mDataSize + addSize, mDataSize + mDataSize/2));
  190. }
  191. void CircularBuffer::Grow(int addSize)
  192. {
  193. GrowReserve(addSize);
  194. mDataSize += addSize;
  195. }
  196. void CircularBuffer::GrowFront(int addSize)
  197. {
  198. if (mDataSize + addSize > mBufSize)
  199. {
  200. Resize(mDataSize + addSize);
  201. }
  202. mDataSize += addSize;
  203. mTail = (mTail + mBufSize - addSize) % mBufSize;
  204. }
  205. int CircularBuffer::GetSize()
  206. {
  207. return mDataSize;
  208. }
  209. void CircularBuffer::MapView(int idx, int len, CircularBuffer::View& view)
  210. {
  211. view.mCircularBuffer = this;
  212. view.mSrcIdx = idx;
  213. view.mSrcSize = len;
  214. if (mTail + idx + len <= mBufSize)
  215. {
  216. view.mPtr = mBuffer + mTail + idx;
  217. }
  218. else
  219. {
  220. if (view.mTempBufSize < len)
  221. {
  222. delete view.mTempBuf;
  223. view.mTempBuf = new uint8[len];
  224. view.mTempBufSize = len;
  225. }
  226. view.mPtr = view.mTempBuf;
  227. Read(view.mTempBuf, idx, len);
  228. }
  229. }
  230. void CircularBuffer::Read(void* ptr, int idx, int len)
  231. {
  232. BF_ASSERT(len <= mBufSize);
  233. if (len == 0)
  234. return;
  235. int absIdx = (mTail + idx) % mBufSize;
  236. if (absIdx + len > mBufSize)
  237. {
  238. int lowSize = mBufSize - absIdx;
  239. memcpy(ptr, mBuffer + absIdx, lowSize);
  240. memcpy((uint8*)ptr + lowSize, mBuffer, len - lowSize);
  241. }
  242. else
  243. {
  244. memcpy(ptr, mBuffer + absIdx, len);
  245. }
  246. }
  247. void CircularBuffer::Write(void* ptr, int idx, int len)
  248. {
  249. BF_ASSERT(len <= mBufSize);
  250. if (len == 0)
  251. return;
  252. int absIdx = (mTail + idx) % mBufSize;
  253. if (absIdx + len > mBufSize)
  254. {
  255. int lowSize = mBufSize - absIdx;
  256. memcpy(mBuffer + absIdx, ptr, lowSize);
  257. memcpy(mBuffer, (uint8*)ptr + lowSize, len - lowSize);
  258. }
  259. else
  260. {
  261. memcpy(mBuffer + absIdx, ptr, len);
  262. }
  263. }
  264. void CircularBuffer::RemoveFront(int len)
  265. {
  266. mTail = (mTail + len) % mBufSize;
  267. mDataSize -= len;
  268. }
  269. //////////////////////////////////////////////////////////////////////////
  270. BpCmdTarget::BpCmdTarget()
  271. {
  272. mCurDynStrIdx = 0;
  273. mCurDepth = 0;
  274. mThreadName = NULL;
  275. }
  276. void BpCmdTarget::Disable()
  277. {
  278. AutoCrit autoCrit(mCritSect);
  279. mOutBuffer.Free();
  280. }
  281. const char* BpCmdTarget::DynamicString(const char* str)
  282. {
  283. int usedIdx = mCurDynStrIdx;
  284. mDynStrs[usedIdx] = str;
  285. mCurDynStrIdx = (mCurDynStrIdx + 1) % BF_ARRAY_COUNT(mDynStrs);
  286. return (const char*)(intptr)usedIdx;
  287. }
  288. const char* BpCmdTarget::ToStrPtr(const char* str)
  289. {
  290. if ((intptr)str < BF_ARRAY_COUNT(mDynStrs))
  291. return mDynStrs[(intptr)str];
  292. return str;
  293. }
  294. #define BPCMD_PREPARE if ((gBpManagerOwner.mDidShutdown) || (!BpManager::Get()->mCollectData)) return; AutoCrit autoCrit(mCritSect)
  295. #define GET_FROM(ptr, T) *((T*)(ptr += sizeof(T)) - 1)
  296. //#define BPCMD_RESERVE(addSize) mOutBuffer.resize(mOutBuffer.size() + (addSize)); uint8* data = &mOutBuffer[mOutBuffer.size() - (addSize)];
  297. #define BPCMD_RESERVE(addSize) uint8* data = mOutBuffer.Alloc(addSize)
  298. #define BPCMD_RESERVE_UNDECL(addSize) data = mOutBuffer.Alloc(addSize)
  299. #define BPCMD_MEMBER(T) *((T*)(data += sizeof(T)) - 1)
  300. #define BPCMD_MEMCPY(ptr, size) memcpy(data, ptr, size); data += size
  301. #define BPCMD_END() BF_ASSERT(data == mOutBuffer.mPtr + mOutBuffer.mDataSize)
  302. static int64 GetTimestamp()
  303. {
  304. #ifdef BF_PLATFORM_WINDOWS
  305. return __rdtsc() / 100;
  306. #else
  307. return BfpSystem_GetCPUTick() / 100;
  308. #endif
  309. }
  310. #define MAX_DEPTH 8192
  311. void BpCmdTarget::Enter(const char* name)
  312. {
  313. BPCMD_PREPARE;
  314. // Failure here could be from unbalanced enter/leave calls
  315. BF_ASSERT((uint32)mCurDepth <= MAX_DEPTH);
  316. if ((intptr)name < BF_ARRAY_COUNT(mDynStrs))
  317. {
  318. const char* dynStr = mDynStrs[(intptr)name];
  319. int len = (int)strlen(dynStr);
  320. BPCMD_RESERVE(1 + 8 + len + 1);
  321. BPCMD_MEMBER(uint8) = BpCmd_EnterDyn;
  322. BPCMD_MEMBER(int64) = GetTimestamp();
  323. BPCMD_MEMCPY(dynStr, len + 1);
  324. BPCMD_END();
  325. }
  326. else
  327. {
  328. BPCMD_RESERVE(1 + 8 + sizeof(const char*));
  329. BPCMD_MEMBER(uint8) = BpCmd_Enter;
  330. BPCMD_MEMBER(int64) = GetTimestamp();
  331. BPCMD_MEMBER(const char*) = name;
  332. BPCMD_END();
  333. }
  334. mCurDepth++;
  335. }
  336. void BpCmdTarget::Enter(const char* name, va_list args)
  337. {
  338. BPCMD_PREPARE;
  339. // Failure here could be from unbalanced enter/leave calls
  340. BF_ASSERT((uint32)mCurDepth <= MAX_DEPTH);
  341. int len = 0;
  342. int paramSize = 0;
  343. //va_list origArgs = args;
  344. va_list origArgs;
  345. va_copy(origArgs, args);
  346. //va_start(args, name);
  347. const char* cPtr = ToStrPtr(name);
  348. while (true)
  349. {
  350. char c = *(cPtr++);
  351. if (c == 0)
  352. break;
  353. len++;
  354. if (c == '%')
  355. {
  356. len++;
  357. char nextC = *(cPtr++);
  358. if (nextC != '%')
  359. {
  360. if (nextC == 'f')
  361. {
  362. va_arg(args, double);
  363. paramSize += 4; // float
  364. }
  365. else if (nextC == 'd')
  366. {
  367. intptr val = va_arg(args, intptr);
  368. paramSize += 4; // int32
  369. }
  370. else if (nextC == 'p')
  371. {
  372. intptr val = va_arg(args, intptr);
  373. paramSize += 8; // int64
  374. }
  375. else if (nextC == 's')
  376. {
  377. const char* str = ToStrPtr(va_arg(args, char*));
  378. paramSize += (int)strlen(str) + 1;
  379. }
  380. else
  381. {
  382. BF_FATAL("Invalid format flag");
  383. }
  384. }
  385. }
  386. }
  387. //va_end(args);
  388. uint8* data;
  389. if ((intptr)name < BF_ARRAY_COUNT(mDynStrs))
  390. {
  391. const char* dynStr = mDynStrs[(intptr)name];
  392. int len = (int)strlen(dynStr);
  393. BPCMD_RESERVE_UNDECL(1 + 8 + len + 1 + paramSize);
  394. BPCMD_MEMBER(uint8) = BpCmd_EnterDyn;
  395. BPCMD_MEMBER(int64) = GetTimestamp();
  396. BPCMD_MEMCPY(dynStr, len + 1);
  397. }
  398. else
  399. {
  400. BPCMD_RESERVE_UNDECL(1 + 8 + sizeof(const char*) + paramSize);
  401. BPCMD_MEMBER(uint8) = BpCmd_Enter;
  402. BPCMD_MEMBER(int64) = GetTimestamp();
  403. BPCMD_MEMBER(const char*) = name;
  404. }
  405. /*BPCMD_RESERVE(1 + 8 + len + 1 + paramSize);
  406. BPCMD_MEMBER(uint8) = BpCmd_Enter;
  407. BPCMD_MEMBER(int64) = GetTimestamp();
  408. BPCMD_MEMCPY(name, len + 1);*/
  409. args = origArgs;
  410. //va_start(args, name);
  411. cPtr = ToStrPtr(name);
  412. while (true)
  413. {
  414. char c = *(cPtr++);
  415. if (c == 0)
  416. break;
  417. if (c == '%')
  418. {
  419. char nextC = *(cPtr++);
  420. if (nextC != '%')
  421. {
  422. if (nextC == 'f')
  423. {
  424. BPCMD_MEMBER(float) = (float)va_arg(args, double);
  425. }
  426. else if (nextC == 'd')
  427. {
  428. BPCMD_MEMBER(int32) = (int32)va_arg(args, intptr);
  429. }
  430. else if (nextC == 'p')
  431. {
  432. BPCMD_MEMBER(int64) = (int64)va_arg(args, intptr);
  433. }
  434. else if (nextC == 's')
  435. {
  436. const char* str = ToStrPtr(va_arg(args, char*));
  437. BPCMD_MEMCPY(str, (int)strlen(str) + 1);
  438. }
  439. else
  440. {
  441. BF_FATAL("Invalid format flag");
  442. }
  443. }
  444. }
  445. }
  446. va_end(args);
  447. BPCMD_END();
  448. mCurDepth++;
  449. }
  450. void BpCmdTarget::EnterF(const char* name, ...)
  451. {
  452. va_list args;
  453. va_start(args, name);
  454. Enter(name, args);
  455. va_end(args);
  456. }
  457. void BpCmdTarget::Leave()
  458. {
  459. BPCMD_PREPARE;
  460. if (mCurDepth <= 0)
  461. {
  462. // This is either due to improperly balanced Enter/Leaves or from a Reconnnect
  463. BF_ASSERT(BpManager::Get()->mInitCount > 1);
  464. return;
  465. }
  466. BPCMD_RESERVE(1 + 8);
  467. BPCMD_MEMBER(uint8) = BpCmd_Leave;
  468. BPCMD_MEMBER(int64) = GetTimestamp();
  469. BPCMD_END();
  470. mCurDepth--;
  471. }
  472. void BpCmdTarget::Event(const char* name, const char* details)
  473. {
  474. name = ToStrPtr(name);
  475. details = ToStrPtr(details);
  476. BPCMD_PREPARE;
  477. int nameLen = (int)strlen(name);
  478. int detailsLen = (int)strlen(details);
  479. BPCMD_RESERVE(1 + 8 + nameLen+1 + detailsLen+1);
  480. BPCMD_MEMBER(uint8) = BpCmd_Event;
  481. BPCMD_MEMBER(int64) = GetTimestamp();
  482. BPCMD_MEMCPY(name, nameLen + 1);
  483. BPCMD_MEMCPY(details, detailsLen + 1);
  484. BPCMD_END();
  485. }
  486. void BpRootCmdTarget::Init()
  487. {
  488. BPCMD_PREPARE;
  489. BPCMD_RESERVE(1);
  490. BPCMD_MEMBER(uint8) = BpCmd_Init;
  491. BPCMD_END();
  492. }
  493. void BpRootCmdTarget::Tick()
  494. {
  495. BPCMD_PREPARE;
  496. BPCMD_RESERVE(1 + 8);
  497. BPCMD_MEMBER(uint8) = BpCmd_Tick;
  498. BPCMD_MEMBER(int64) = GetTimestamp();
  499. BPCMD_END();
  500. }
  501. void BpRootCmdTarget::KeepAlive()
  502. {
  503. BPCMD_PREPARE;
  504. BPCMD_RESERVE(1 + 8);
  505. BPCMD_MEMBER(uint8) = BpCmd_KeepAlive;
  506. BPCMD_MEMBER(int64) = GetTimestamp();
  507. BPCMD_END();
  508. }
  509. void BpRootCmdTarget::AddThread(int threadId, BfpThreadId nativeThreadId)
  510. {
  511. BPCMD_PREPARE;
  512. BPCMD_RESERVE(1 + 8 + 4 + 4);
  513. BPCMD_MEMBER(uint8) = BpCmd_ThreadAdd;
  514. BPCMD_MEMBER(int64) = GetTimestamp();
  515. BPCMD_MEMBER(int32) = threadId;
  516. BPCMD_MEMBER(int32) = (int32)nativeThreadId;
  517. BPCMD_END();
  518. }
  519. BpThreadInfo::BpThreadInfo()
  520. {
  521. mNativeThreadId = -1;
  522. mThreadId = 0;
  523. mReadyToSend = false;
  524. mHasTerminated = false;
  525. }
  526. BpThreadInfo::~BpThreadInfo()
  527. {
  528. if (mThreadName != NULL)
  529. BpManager::Get()->FreeBytes(mThreadName);
  530. }
  531. void BpThreadInfo::SetThreadName(const char* name)
  532. {
  533. int len = (int)strlen(name);
  534. if (mThreadName == NULL)
  535. {
  536. mThreadName = (char*)BpManager::Get()->AllocBytes(len + 1);
  537. memcpy(mThreadName, name, len + 1);
  538. }
  539. BPCMD_PREPARE;
  540. BPCMD_RESERVE(1 + len + 1);
  541. BPCMD_MEMBER(uint8) = BpCmd_ThreadName;
  542. BPCMD_MEMCPY(name, len + 1);
  543. BPCMD_END();
  544. }
  545. void BpThreadInfo::RemoveThread()
  546. {
  547. BPCMD_PREPARE;
  548. BPCMD_RESERVE(1 + 8);
  549. BPCMD_MEMBER(uint8) = BpCmd_ThreadRemove;
  550. BPCMD_MEMBER(int64) = GetTimestamp();
  551. BPCMD_END();
  552. }
  553. //////////////////////////////////////////////////////////////////////////
  554. static void NTAPI FlsFreeFunc(void* ptr)
  555. {
  556. BpThreadInfo* threadInfo = (BpThreadInfo*)ptr;
  557. auto bpManager = BpManager::Get();
  558. AutoCrit autoCrit(bpManager->mCritSect);
  559. threadInfo->mHasTerminated = true;
  560. threadInfo->RemoveThread();
  561. if (!bpManager->mThreadRunning)
  562. {
  563. bpManager->mThreadInfos.Remove(threadInfo);
  564. delete threadInfo;
  565. // It's possible that other thread-specific destructors will occur after this call, which may use BeefPerf,
  566. // and in that case we will re-add this thread info
  567. BpManager::sBpThreadInfo = NULL;
  568. }
  569. }
  570. BpManager::BpManager() : mShutdownEvent(true), mTLSDtor(&FlsFreeFunc)
  571. {
  572. #ifdef BF_PLATFORM_WINDOWS
  573. mMutex = NULL;
  574. mSharedMemoryFile = NULL;
  575. #endif
  576. mSocket = INVALID_SOCKET;
  577. mConnectState = BpConnectState_NotConnected;
  578. mThread = NULL;
  579. mThreadId = 0;
  580. mCurTick = 0;
  581. mCurThreadId = 0;
  582. mOutBlockSizeLeft = 0;
  583. mPauseCount = 0;
  584. mInitCount = 0;
  585. mCollectData = false;
  586. mThreadRunning = false;
  587. mInitTimeStamp = GetTimestamp();
  588. mInitTickCount = BFTickCount();
  589. }
  590. BpManager::~BpManager()
  591. {
  592. Shutdown();
  593. #ifdef BF_PLATFORM_WINDOWS
  594. if (mMutex != NULL)
  595. ::CloseHandle(mMutex);
  596. if (mSharedMemoryFile != NULL)
  597. ::CloseHandle(mSharedMemoryFile);
  598. #endif
  599. }
  600. bool BpManager::Connect()
  601. {
  602. struct sockaddr_in server;
  603. struct hostent * hp;
  604. server.sin_family = PF_INET;
  605. hp = gethostbyname(mServerName.c_str());
  606. if (hp == NULL)
  607. return false;
  608. memcpy(&server.sin_addr, hp->h_addr_list[0], sizeof(server.sin_addr));
  609. server.sin_port = htons(4208);
  610. #ifdef BF_PLATFORM_WINDOWS
  611. bool isLocalhost = server.sin_addr.S_un.S_addr == 0x0100007f;
  612. #else
  613. bool isLocalhost = server.sin_addr.s_addr == 0x0100007f;
  614. #endif
  615. int result = ::connect(mSocket, (sockaddr*)&server, sizeof(server));
  616. if (result != 0)
  617. {
  618. #ifdef BF_PLATFORM_WINDOWS
  619. int err = WSAGetLastError();
  620. if (err != WSAEWOULDBLOCK)
  621. return false;
  622. #else
  623. if (errno != EINPROGRESS)
  624. return false;
  625. #endif
  626. }
  627. int totalWaitedMS = 0;
  628. // Wait for connection - normally we wait for either the connection to occur or an error to occur,
  629. // but if we shutdown the app then we need to ensure we waited "long enough", but we don't want
  630. // to keep very short programs from exiting in a timely manner so we have a short localhost timeout
  631. // since Windows will delay for 2s before failing
  632. while (true)
  633. {
  634. int selectTimeoutMS = 20;
  635. timeval timeout;
  636. timeout.tv_sec = 0;
  637. timeout.tv_usec = selectTimeoutMS * 1000;
  638. FD_SET socketWriteSet;
  639. FD_ZERO(&socketWriteSet);
  640. FD_SET(mSocket, &socketWriteSet);
  641. FD_SET socketErrorSet;
  642. FD_ZERO(&socketErrorSet);
  643. FD_SET(mSocket, &socketErrorSet);
  644. int result = select((int)mSocket + 1, NULL, &socketWriteSet, &socketErrorSet, &timeout);
  645. if (result == -1)
  646. return false;
  647. if (FD_ISSET(mSocket, &socketWriteSet))
  648. break;
  649. if (FD_ISSET(mSocket, &socketErrorSet))
  650. return false;
  651. totalWaitedMS += selectTimeoutMS;
  652. if (mShutdownEvent.WaitFor(0))
  653. {
  654. // We are shutting down - have we waited enough?
  655. int minWaitMS = isLocalhost ? 50 : 5*1000;
  656. if (totalWaitedMS >= minWaitMS)
  657. return false;
  658. }
  659. // We don't want to wait too long, otherwise we will buffer up too much
  660. int maxWaitMS = isLocalhost ? 5*1000 : 15*1000;
  661. if (totalWaitedMS >= maxWaitMS)
  662. return false;
  663. }
  664. return true;
  665. }
  666. uint8* BpManager::StartCmd(uint8 cmd, CircularBuffer::View& view, int maxLen)
  667. {
  668. mOutBuffer.GrowReserve(maxLen);
  669. mOutBuffer.MapView(mOutBuffer.GetSize(), maxLen, view);
  670. uint8* dataOut = view.mPtr;
  671. GET_FROM(dataOut, uint8) = cmd;
  672. return dataOut;
  673. }
  674. void BpManager::EndCmd(CircularBuffer::View& view, uint8* ptr)
  675. {
  676. int actualSize = (int)(ptr - view.mPtr);
  677. view.Commit(actualSize);
  678. mOutBuffer.Grow(actualSize);
  679. }
  680. void BpManager::TrySendData()
  681. {
  682. CircularBuffer::View outView;
  683. while (true)
  684. {
  685. int sizeLeft = mOutBuffer.GetSize();
  686. if (sizeLeft == 0)
  687. return;
  688. int trySend = std::min(sizeLeft, 8192);
  689. mOutBuffer.MapView(0, trySend, outView);
  690. int result = send(mSocket, (const char*)outView.mPtr, trySend, 0);
  691. if (result < 0)
  692. {
  693. #ifdef BF_PLATFORM_WINDOWS
  694. int err = WSAGetLastError();
  695. switch (err)
  696. {
  697. case WSAECONNABORTED:
  698. case WSAECONNRESET:
  699. mConnectState = BpConnectState_NotConnected;
  700. }
  701. #else
  702. switch (errno)
  703. {
  704. case ECONNRESET:
  705. mConnectState = BpConnectState_NotConnected;
  706. }
  707. #endif
  708. return;
  709. }
  710. mOutBuffer.RemoveFront(result);
  711. }
  712. }
  713. void BpManager::LostConnection()
  714. {
  715. mCollectData = false;
  716. AutoCrit autoCrit(mCritSect);
  717. mRootCmdTarget.Disable();
  718. for (auto threadInfo : mThreadInfos)
  719. threadInfo->Disable();
  720. #ifdef BF_PLATFORM_WINDOWS
  721. closesocket(mSocket);
  722. #else
  723. close(mSocket);
  724. #endif
  725. mSocket = INVALID_SOCKET;
  726. }
  727. BpThreadInfo* BpManager::SlowGetCurThreadInfo()
  728. {
  729. BfpThreadId curThreadId = BfpThread_GetCurrentId();
  730. // Try to find an existing one
  731. {
  732. AutoCrit autoCrit(mCritSect);
  733. for (auto threadInfo : mThreadInfos)
  734. if (threadInfo->mNativeThreadId == curThreadId)
  735. return threadInfo;
  736. }
  737. auto threadInfo = new BpThreadInfo();
  738. threadInfo->mThreadId = mCurThreadId++;
  739. threadInfo->mNativeThreadId = curThreadId;
  740. sBpThreadInfo = threadInfo;
  741. AutoCrit autoCrit(mCritSect);
  742. mThreadInfos.push_back(threadInfo);
  743. if (mThreadRunning)
  744. mRootCmdTarget.AddThread(threadInfo->mThreadId, threadInfo->mNativeThreadId);
  745. mTLSDtor.Add((void*)threadInfo);
  746. return threadInfo;
  747. }
  748. void* BpManager::AllocBytes(int size)
  749. {
  750. return new uint8[size];
  751. }
  752. void BpManager::FreeBytes(void* ptr)
  753. {
  754. delete [] (uint8*)ptr;
  755. }
  756. void BpManager::FinishWorkThread()
  757. {
  758. AutoCrit autoCrit(mCritSect);
  759. for (int i = 0; i < (int)mThreadInfos.size(); i++)
  760. {
  761. auto threadInfo = mThreadInfos[i];
  762. if (threadInfo->mHasTerminated)
  763. {
  764. delete threadInfo;
  765. mThreadInfos.erase(mThreadInfos.begin() + i);
  766. i--;
  767. }
  768. }
  769. mThreadRunning = false;
  770. }
  771. void BpManager::ThreadProc()
  772. {
  773. BfpThread_SetName(NULL, "BeefPerf", NULL);
  774. if (!Connect())
  775. {
  776. mConnectState = BpConnectState_Failed;
  777. LostConnection();
  778. FinishWorkThread();
  779. return;
  780. }
  781. Buffer threadBuffer;
  782. String tempStr;
  783. CircularBuffer::View outView;
  784. timeval timeout;
  785. timeout.tv_sec = 0;
  786. timeout.tv_usec = 20 * 1000; // 20ms
  787. uint32 gLastMsgTick = BFTickCount();
  788. DWORD lastTimeTick = 0;
  789. while (mConnectState != BpConnectState_NotConnected)
  790. {
  791. bool wantsExit = mShutdownEvent.WaitFor(0);
  792. FD_SET socketReadSet;
  793. FD_ZERO(&socketReadSet);
  794. FD_SET(mSocket, &socketReadSet);
  795. FD_SET socketWriteSet;
  796. FD_ZERO(&socketWriteSet);
  797. if (mOutBuffer.GetSize() > 0)
  798. FD_SET(mSocket, &socketWriteSet);
  799. FD_SET socketErrorSet;
  800. FD_ZERO(&socketErrorSet);
  801. FD_SET(mSocket, &socketErrorSet);
  802. int selResult = select((int)mSocket + 1, &socketReadSet, &socketWriteSet, &socketErrorSet, &timeout);
  803. if (FD_ISSET(mSocket, &socketWriteSet))
  804. {
  805. TrySendData();
  806. //continue;
  807. }
  808. if (FD_ISSET(mSocket, &socketReadSet))
  809. {
  810. // Just eat the data
  811. uint8 data[4096];
  812. int len = recv(mSocket, (char*)data, 4096, 0);
  813. int b = 0;
  814. }
  815. if (FD_ISSET(mSocket, &socketErrorSet))
  816. {
  817. #ifdef BF_PLATFORM_WINDOWS
  818. int err = WSAGetLastError();
  819. #endif
  820. mConnectState = BpConnectState_NotConnected;
  821. LostConnection();
  822. FinishWorkThread();
  823. return;
  824. }
  825. // Alloc space for size
  826. mOutBuffer.Grow(4);
  827. int startBufferSize = mOutBuffer.GetSize();
  828. int threadIdx = -1;
  829. int threadId = -1;
  830. //
  831. {
  832. // We need to send the BpCmd_ThreadAdd before sending any data from the thread,
  833. AutoCrit autoCrit(mCritSect);
  834. for (int threadIdx = 0; threadIdx < (int)mThreadInfos.size(); threadIdx++)
  835. {
  836. auto threadInfo = mThreadInfos[threadIdx];
  837. if ((threadInfo->mHasTerminated) && (threadInfo->mOutBuffer.mDataSize == 0))
  838. {
  839. mThreadInfos.erase(mThreadInfos.begin() + threadIdx);
  840. delete threadInfo;
  841. threadIdx--;
  842. }
  843. else
  844. {
  845. threadInfo->mReadyToSend = true;
  846. }
  847. }
  848. }
  849. while (true)
  850. {
  851. BpCmdTarget* cmdTarget = NULL;
  852. if (threadIdx == -1)
  853. {
  854. cmdTarget = &mRootCmdTarget;
  855. threadIdx++;
  856. }
  857. else
  858. {
  859. AutoCrit autoCrit(mCritSect);
  860. if (threadIdx >= (int)mThreadInfos.size())
  861. break;
  862. auto threadInfo = mThreadInfos[threadIdx++];
  863. threadId = threadInfo->mThreadId;
  864. cmdTarget = threadInfo;
  865. if (!threadInfo->mReadyToSend)
  866. continue;
  867. }
  868. //
  869. {
  870. AutoCrit autoCrit(cmdTarget->mCritSect);
  871. BF_ASSERT(threadBuffer.mDataSize == 0);
  872. memcpy(threadBuffer.Alloc(cmdTarget->mOutBuffer.mDataSize), cmdTarget->mOutBuffer.mPtr, cmdTarget->mOutBuffer.mDataSize);
  873. cmdTarget->mOutBuffer.Clear();
  874. }
  875. if (threadBuffer.mDataSize == 0)
  876. continue;
  877. uint8* dataOut = StartCmd(BpCmd_SetThread, outView, 5);
  878. EncodeSLEB128(dataOut, threadId);
  879. EndCmd(outView, dataOut);
  880. uint8* dataIn = threadBuffer.mPtr;
  881. uint8* dataInEnd = dataIn + threadBuffer.mDataSize;
  882. static int sIdx = 0;
  883. while (dataIn < dataInEnd)
  884. {
  885. BpCmd cmd = (BpCmd)*(dataIn++);
  886. int nameMsgLen;
  887. if (cmd == BpCmd_Init)
  888. {
  889. AutoCrit autoCrit(mRootCmdTarget.mCritSect);
  890. String env;
  891. env += "SessionID\t";
  892. env += mSessionID;
  893. env += "\n";
  894. if (!mSessionName.IsEmpty())
  895. {
  896. env += "SessionName\t";
  897. env += mSessionName;
  898. env += "\n";
  899. }
  900. if (!mClientName.IsEmpty())
  901. {
  902. env += "ClientName\t";
  903. env += mClientName;
  904. env += "\n";
  905. }
  906. int32 nameLen = (int32)env.length();
  907. uint8* dataOut = StartCmd(BpCmd_Init, outView, 1 + 4 + nameLen + 1);
  908. EncodeSLEB128(dataOut, BP_CLIENT_VERSION);
  909. memcpy(dataOut, env.c_str(), nameLen + 1);
  910. dataOut += nameLen + 1;
  911. EndCmd(outView, dataOut);
  912. dataOut = StartCmd(BpCmd_ClockInfo, outView, 1 + 8 + 8 + 8 + 1);
  913. EncodeSLEB128(dataOut, mCurTick);
  914. EncodeSLEB128(dataOut, GetTimestamp());
  915. EncodeSLEB128(dataOut, (int)BFTickCount());
  916. EncodeSLEB128(dataOut, BfpSystem_GetCPUTickFreq());
  917. EndCmd(outView, dataOut);
  918. }
  919. else if ((cmd == BpCmd_Enter) || (cmd == BpCmd_EnterDyn))
  920. {
  921. int64 tick = GET_FROM(dataIn, int64);
  922. const char* name;
  923. int strIdx;
  924. int paramsSize = 0;
  925. if (cmd == BpCmd_EnterDyn)
  926. {
  927. name = (const char*)dataIn;
  928. int nameLen = (int)strlen(name);
  929. dataIn += nameLen + 1;
  930. paramsSize = -1;
  931. strIdx = -nameLen;
  932. nameMsgLen = 4+1 + nameLen;
  933. }
  934. else
  935. {
  936. name = GET_FROM(dataIn, const char*);
  937. BpZoneName* zoneName;
  938. if (mZoneNameMap.TryAdd(name, NULL, &zoneName))
  939. {
  940. int nameLen = (int)strlen(name);
  941. strIdx = (int)mZoneNameMap.size() - 1;
  942. zoneName->mIdx = strIdx;
  943. zoneName->mSize = 0;
  944. bool isDyn = false;
  945. const char* cPtr = name;
  946. while (true)
  947. {
  948. char c = *(cPtr++);
  949. if (c == 0)
  950. break;
  951. if (c == '%')
  952. {
  953. char nextC = *(cPtr++);
  954. if (nextC != '%')
  955. {
  956. if (nextC == 'f')
  957. {
  958. zoneName->mSize += 4;
  959. }
  960. else if (nextC == 'd')
  961. {
  962. zoneName->mSize += 4;
  963. }
  964. else if (nextC == 'p')
  965. {
  966. zoneName->mSize += 8;
  967. }
  968. else if (nextC == 's')
  969. {
  970. isDyn = true;
  971. }
  972. }
  973. }
  974. }
  975. if (isDyn)
  976. zoneName->mSize = -1;
  977. uint8* dataOut = StartCmd(BpCmd_StrEntry, outView, 1 + nameLen + 1);
  978. memcpy(dataOut, name, nameLen + 1);
  979. dataOut += nameLen + 1;
  980. EndCmd(outView, dataOut);
  981. paramsSize = zoneName->mSize;
  982. }
  983. else
  984. {
  985. strIdx = zoneName->mIdx;
  986. paramsSize = zoneName->mSize;
  987. }
  988. nameMsgLen = 4+1;
  989. }
  990. bool isDynSize = false;
  991. int addParamSize = 0;
  992. if (paramsSize == -1)
  993. {
  994. isDynSize = true;
  995. addParamSize = 4 + 1; // For size param
  996. // Calc size
  997. auto checkDataIn = dataIn;
  998. const char* cPtr = name;
  999. while (true)
  1000. {
  1001. char c = *(cPtr++);
  1002. if (c == 0)
  1003. break;
  1004. if (c == '%')
  1005. {
  1006. char nextC = *(cPtr++);
  1007. if (nextC != '%')
  1008. {
  1009. if (nextC == 'f')
  1010. {
  1011. checkDataIn += 4;
  1012. }
  1013. else if (nextC == 'd')
  1014. {
  1015. checkDataIn += 4;
  1016. }
  1017. else if (nextC == 'p')
  1018. {
  1019. checkDataIn += 8;
  1020. }
  1021. else if (nextC == 's')
  1022. {
  1023. int len = (int)strlen((const char*)checkDataIn);
  1024. checkDataIn += len + 1;
  1025. }
  1026. }
  1027. }
  1028. }
  1029. paramsSize = (int)(checkDataIn - dataIn);
  1030. }
  1031. uint8* dataOut = StartCmd(BpCmd_Enter, outView, 1 + 8+1 + nameMsgLen + paramsSize + addParamSize);
  1032. int64 tickDelta = tick - mCurTick;
  1033. mCurTick = tick;
  1034. EncodeSLEB128(dataOut, tickDelta);
  1035. if (strIdx < 0)
  1036. {
  1037. EncodeSLEB128(dataOut, strIdx);
  1038. memcpy(dataOut, name, -strIdx);
  1039. dataOut += -strIdx;
  1040. }
  1041. else
  1042. EncodeSLEB128(dataOut, strIdx);
  1043. if (isDynSize)
  1044. EncodeSLEB128(dataOut, paramsSize);
  1045. if (paramsSize != 0)
  1046. {
  1047. memcpy(dataOut, dataIn, paramsSize);
  1048. dataOut += paramsSize;
  1049. dataIn += paramsSize;
  1050. }
  1051. EndCmd(outView, dataOut);
  1052. }
  1053. else if (cmd == BpCmd_Leave)
  1054. {
  1055. uint8* dataOut = StartCmd(BpCmd_Leave, outView, 1 + 8+1);
  1056. int64 tick = GET_FROM(dataIn, int64);
  1057. int64 tickDelta = tick - mCurTick;
  1058. mCurTick = tick;
  1059. EncodeSLEB128(dataOut, tickDelta);
  1060. EndCmd(outView, dataOut);
  1061. }
  1062. else if (cmd == BpCmd_ThreadName)
  1063. {
  1064. const char* name = (const char*)dataIn;
  1065. int nameLen = (int)strlen(name);
  1066. uint8* dataOut = StartCmd(BpCmd_ThreadName, outView, 1 + nameLen + 1);
  1067. memcpy(dataOut, dataIn, nameLen + 1);
  1068. dataIn += nameLen + 1;
  1069. dataOut += nameLen + 1;
  1070. EndCmd(outView, dataOut);
  1071. }
  1072. else if (cmd == BpCmd_Tick)
  1073. {
  1074. uint8* dataOut = StartCmd(BpCmd_Tick, outView, 1 + 8+1);
  1075. int64 tick = GET_FROM(dataIn, int64);
  1076. int64 tickDelta = tick - mCurTick;
  1077. mCurTick = tick;
  1078. EncodeSLEB128(dataOut, tickDelta);
  1079. EndCmd(outView, dataOut);
  1080. }
  1081. else if (cmd == BpCmd_KeepAlive)
  1082. {
  1083. uint8* dataOut = StartCmd(BpCmd_KeepAlive, outView, 1 + 8+1);
  1084. int64 tick = GET_FROM(dataIn, int64);
  1085. int64 tickDelta = tick - mCurTick;
  1086. mCurTick = tick;
  1087. EncodeSLEB128(dataOut, tickDelta);
  1088. EndCmd(outView, dataOut);
  1089. }
  1090. else if (cmd == BpCmd_ThreadAdd)
  1091. {
  1092. uint8* dataOut = StartCmd(BpCmd_ThreadAdd, outView, 1 + 8+1 + 4+1 + 4+1);
  1093. int64 tick = GET_FROM(dataIn, int64);
  1094. int64 tickDelta = tick - mCurTick;
  1095. mCurTick = tick;
  1096. int32 threadId = GET_FROM(dataIn, int32);
  1097. int32 nativeThreadId = GET_FROM(dataIn, int32);
  1098. EncodeSLEB128(dataOut, tickDelta);
  1099. EncodeSLEB128(dataOut, threadId);
  1100. EncodeSLEB128(dataOut, nativeThreadId);
  1101. EndCmd(outView, dataOut);
  1102. }
  1103. else if (cmd == BpCmd_ThreadRemove)
  1104. {
  1105. uint8* dataOut = StartCmd(BpCmd_ThreadRemove, outView, 1 + 8+1);
  1106. int64 tick = GET_FROM(dataIn, int64);
  1107. int64 tickDelta = tick - mCurTick;
  1108. mCurTick = tick;
  1109. EncodeSLEB128(dataOut, tickDelta);
  1110. EndCmd(outView, dataOut);
  1111. }
  1112. else if (cmd == BpCmd_Event)
  1113. {
  1114. int64 tick = GET_FROM(dataIn, int64);
  1115. int64 tickDelta = tick - mCurTick;
  1116. mCurTick = tick;
  1117. const char* name = (const char*)dataIn;
  1118. int nameLen = (int)strlen(name);
  1119. const char* details = (const char*)(dataIn + nameLen + 1);
  1120. int detailsLen = (int)strlen(details);
  1121. uint8* dataOut = StartCmd(BpCmd_Event, outView, 1 + 8+1 + nameLen + 1 + detailsLen + 1);
  1122. EncodeSLEB128(dataOut, tickDelta);
  1123. memcpy(dataOut, dataIn, nameLen + 1);
  1124. dataIn += nameLen + 1;
  1125. dataOut += nameLen + 1;
  1126. memcpy(dataOut, dataIn, detailsLen + 1);
  1127. dataIn += detailsLen + 1;
  1128. dataOut += detailsLen + 1;
  1129. EndCmd(outView, dataOut);
  1130. }
  1131. else
  1132. BF_FATAL("Not handled");
  1133. // If we get a large backlog then try to break it up into smaller chunks and send out periodically
  1134. int bufSizeAdded = mOutBuffer.GetSize() - startBufferSize;
  1135. BF_ASSERT(bufSizeAdded >= 0);
  1136. if (bufSizeAdded >= 64*1024)
  1137. {
  1138. // Set chunk size
  1139. CircularBuffer::View view;
  1140. mOutBuffer.MapView(startBufferSize - 4, 4, view);
  1141. uint8* data = view.mPtr;
  1142. GET_FROM(data, int32) = bufSizeAdded;
  1143. view.Commit();
  1144. // We can attempt some more sending now...
  1145. TrySendData();
  1146. // Start next header
  1147. mOutBuffer.Grow(4);
  1148. startBufferSize = mOutBuffer.GetSize();
  1149. }
  1150. }
  1151. threadBuffer.Clear();
  1152. }
  1153. int bufSizeAdded = mOutBuffer.GetSize() - startBufferSize;
  1154. DWORD curTick = BFTickCount();
  1155. // Encode clock info
  1156. if ((lastTimeTick == 0) || ((bufSizeAdded > 0) && (curTick - lastTimeTick >= 1000)))
  1157. {
  1158. uint8* dataOut = StartCmd(BpCmd_ClockInfo, outView, 1 + 8 + 8 + 8 + 1);
  1159. EncodeSLEB128(dataOut, mCurTick);
  1160. EncodeSLEB128(dataOut, GetTimestamp());
  1161. EncodeSLEB128(dataOut, (int)BFTickCount());
  1162. EncodeSLEB128(dataOut, BfpSystem_GetCPUTickFreq());
  1163. EndCmd(outView, dataOut);
  1164. lastTimeTick = curTick;
  1165. }
  1166. bufSizeAdded = mOutBuffer.GetSize() - startBufferSize;
  1167. //BF_ASSERT((bufSizeAdded <= 64*1024) && (bufSizeAdded >= 0));
  1168. if (bufSizeAdded != 0)
  1169. {
  1170. // Set chunk size
  1171. CircularBuffer::View view;
  1172. mOutBuffer.MapView(startBufferSize - 4, 4, view);
  1173. uint8* data = view.mPtr;
  1174. GET_FROM(data, int32) = bufSizeAdded;
  1175. view.Commit();
  1176. }
  1177. else
  1178. mOutBuffer.Grow(-4); // No data added, pop chunk size off
  1179. if (mOutBuffer.GetSize() == 0)
  1180. {
  1181. if (wantsExit)
  1182. {
  1183. break;
  1184. }
  1185. uint32 tickNow = BFTickCount();
  1186. if ((tickNow - gLastMsgTick >= 1000) /*&& (!wantsExit)*/)
  1187. {
  1188. mRootCmdTarget.KeepAlive();
  1189. }
  1190. }
  1191. else
  1192. {
  1193. gLastMsgTick = BFTickCount();
  1194. }
  1195. }
  1196. mOutBuffer.Clear();
  1197. mConnectState = BpConnectState_NotConnected;
  1198. closesocket(mSocket);
  1199. mSocket = INVALID_SOCKET;
  1200. FinishWorkThread();
  1201. }
  1202. void BFP_CALLTYPE BpManager::ThreadProcThunk(void* ptr)
  1203. {
  1204. ((BpManager*)ptr)->ThreadProc();
  1205. }
  1206. void BpManager::Clear()
  1207. {
  1208. int threadIdx = 0;
  1209. while (true)
  1210. {
  1211. BpThreadInfo* threadInfo = NULL;
  1212. //
  1213. {
  1214. AutoCrit autoCrit(mCritSect);
  1215. if (threadIdx >= (int)mThreadInfos.size())
  1216. break;
  1217. threadInfo = mThreadInfos[threadIdx++];
  1218. }
  1219. AutoCrit autoCrit(threadInfo->mCritSect);
  1220. threadInfo->mOutBuffer.Clear();
  1221. }
  1222. }
  1223. void BpManager::SetClientName(const StringImpl& clientName)
  1224. {
  1225. AutoCrit autoCrit(mRootCmdTarget.mCritSect);
  1226. mClientName = clientName;
  1227. }
  1228. BpResult BpManager::Init(const char* serverName, const char* sessionName)
  1229. {
  1230. if (serverName == NULL)
  1231. {
  1232. FinishWorkThread();
  1233. return BpResult_Ok;
  1234. }
  1235. if (mSocket != INVALID_SOCKET)
  1236. return BpResult_AlreadyInitialized;
  1237. BfpGUID guid;
  1238. BfpSystem_CreateGUID(&guid);
  1239. mSessionID = StrFormat("%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
  1240. guid.mData1, guid.mData2, guid.mData3,
  1241. guid.mData4[0], guid.mData4[1], guid.mData4[2], guid.mData4[3],
  1242. guid.mData4[4], guid.mData4[5], guid.mData4[6], guid.mData4[7]);
  1243. if (mClientName.IsEmpty())
  1244. {
  1245. BfpSystemResult result;
  1246. BFP_GETSTR_HELPER(mClientName, result, BfpSystem_GetComputerName(__STR, __STRLEN, &result));
  1247. }
  1248. #ifdef BF_PLATFORM_WINDOWS
  1249. WSADATA wsa;
  1250. int result = WSAStartup(MAKEWORD(2, 0), &wsa);
  1251. if (result != 0)
  1252. {
  1253. return BpResult_InternalError;
  1254. }
  1255. #endif
  1256. mSocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
  1257. if (mSocket == INVALID_SOCKET)
  1258. return BpResult_InternalError;
  1259. u_long iMode = 1;
  1260. #ifdef BF_PLATFORM_WINDOWS
  1261. result = ioctlsocket(mSocket, FIONBIO, &iMode);
  1262. #else
  1263. int result = ioctl(mSocket, FIONBIO, &iMode);
  1264. #endif
  1265. AutoCrit autoCrit(mCritSect);
  1266. AutoCrit autoCrit2(mRootCmdTarget.mCritSect);
  1267. mInitCount++;
  1268. mThreadRunning = true;
  1269. mCollectData = true;
  1270. mServerName = serverName;
  1271. mSessionName = sessionName;
  1272. mConnectState = BpConnectState_Connecting;
  1273. mCurTick = 0;
  1274. mZoneNameMap.Clear();
  1275. bool isReinit = mInitCount > 1;
  1276. if (isReinit)
  1277. {
  1278. // We may have old data in the command targets, so clear all that out
  1279. mRootCmdTarget.Disable();
  1280. for (auto threadInfo : mThreadInfos)
  1281. {
  1282. AutoCrit autoCrit(mCritSect);
  1283. threadInfo->Disable();
  1284. if (threadInfo->mThreadName != NULL)
  1285. threadInfo->SetThreadName(threadInfo->mThreadName);
  1286. threadInfo->mCurDepth = 0;
  1287. }
  1288. }
  1289. for (auto threadInfo : mThreadInfos)
  1290. {
  1291. mRootCmdTarget.AddThread(threadInfo->mThreadId, threadInfo->mNativeThreadId);
  1292. }
  1293. mRootCmdTarget.Init();
  1294. mThread = BfpThread_Create(ThreadProcThunk, (void*)this, 512 * 1024, BfpThreadCreateFlag_StackSizeReserve, &mThreadId);
  1295. return BpResult_Ok;
  1296. }
  1297. void BpManager::RetryConnect()
  1298. {
  1299. {
  1300. AutoCrit autoCrit(mCritSect);
  1301. if ((mConnectState == BpConnectState_Connecting) ||
  1302. (mConnectState == BpConnectState_Connected))
  1303. return;
  1304. }
  1305. Shutdown();
  1306. Init(mServerName.c_str(), mSessionName.c_str());
  1307. }
  1308. void BpManager::Pause()
  1309. {
  1310. BfpSystem_InterlockedExchangeAdd32((uint32*)&mPauseCount, 1);
  1311. }
  1312. void BpManager::Unpause()
  1313. {
  1314. BfpSystem_InterlockedExchangeAdd32((uint32*)&mPauseCount, -1);
  1315. }
  1316. void BpManager::Shutdown()
  1317. {
  1318. BfpThread* workerThread = NULL;
  1319. {
  1320. AutoCrit autoCrit(mCritSect);
  1321. mCollectData = false;
  1322. workerThread = mThread;
  1323. if (workerThread != NULL)
  1324. mShutdownEvent.Set(true);
  1325. }
  1326. if (workerThread != NULL)
  1327. {
  1328. BfpThread_WaitFor(mThread, -1);
  1329. mShutdownEvent.Reset();
  1330. }
  1331. }
  1332. bool BpManager::IsDisconnected()
  1333. {
  1334. return mConnectState == BpConnectState_NotConnected;
  1335. }
  1336. BpContext* Beefy::BpManager::CreateContext(const char* name)
  1337. {
  1338. return nullptr;
  1339. }
  1340. void Beefy::BpManager::CloseContext()
  1341. {
  1342. }
  1343. void BpManager::Tick()
  1344. {
  1345. mRootCmdTarget.Tick();
  1346. }
  1347. BpThreadInfo* BpManager::GetCurThreadInfo()
  1348. {
  1349. BpThreadInfo* threadInfo = sBpThreadInfo;
  1350. if (threadInfo == NULL)
  1351. {
  1352. if (gBpManagerOwner.mDidShutdown)
  1353. return &sFakeThreadInfo;
  1354. threadInfo = Get()->SlowGetCurThreadInfo();
  1355. sBpThreadInfo = threadInfo;
  1356. }
  1357. return threadInfo;
  1358. }
  1359. struct BpSharedMemory
  1360. {
  1361. public:
  1362. BpManager* mBpManager;
  1363. int mABIVersion;
  1364. };
  1365. BpManager* BpManager::Get()
  1366. {
  1367. if (sBpManager != NULL)
  1368. return sBpManager;
  1369. #ifdef BF_PLATFORM_WINDOWS
  1370. char mutexName[128];
  1371. sprintf(mutexName, "BeefPerf_mutex_%d", GetCurrentProcessId());
  1372. char memName[128];
  1373. sprintf(memName, "BeefPerf_mem_%d", GetCurrentProcessId());
  1374. auto mutex = ::CreateMutexA(NULL, TRUE, mutexName);
  1375. if (mutex != NULL)
  1376. {
  1377. HANDLE fileMapping = ::OpenFileMappingA(FILE_MAP_ALL_ACCESS, FALSE, memName);
  1378. if (fileMapping != NULL)
  1379. {
  1380. BpSharedMemory* sharedMem = (BpSharedMemory*)MapViewOfFile(fileMapping, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(BpSharedMemory));
  1381. if (sharedMem != NULL)
  1382. {
  1383. if (sharedMem->mABIVersion == BP_ABI_VERSION)
  1384. {
  1385. sBpManager = sharedMem->mBpManager;
  1386. }
  1387. else
  1388. OutputDebugStringA("*** BeefPerf ABI mismatch! ***\r\n");
  1389. ::UnmapViewOfFile(sharedMem);
  1390. }
  1391. else
  1392. BF_FATAL("BpManager::Get MapViewOfFile error");
  1393. ::CloseHandle(fileMapping);
  1394. }
  1395. else
  1396. {
  1397. fileMapping = ::CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(BpSharedMemory), memName);
  1398. if (fileMapping != NULL)
  1399. {
  1400. BpSharedMemory* sharedMem = (BpSharedMemory*)MapViewOfFile(fileMapping, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(BpSharedMemory));
  1401. if (sharedMem != NULL)
  1402. {
  1403. sBpManager = new BpManager();
  1404. sBpManager->mMutex = mutex;
  1405. sBpManager->mSharedMemoryFile = fileMapping;
  1406. sharedMem->mBpManager = sBpManager;
  1407. sharedMem->mABIVersion = BP_ABI_VERSION;
  1408. ::UnmapViewOfFile(sharedMem);
  1409. ::ReleaseMutex(mutex);
  1410. gBpManagerOwner.mOwnedManager = sBpManager;
  1411. }
  1412. else
  1413. {
  1414. BF_FATAL("BpManager::Get MapViewOfFile error");
  1415. ::CloseHandle(fileMapping);
  1416. ::CloseHandle(mutex);
  1417. }
  1418. }
  1419. else
  1420. BF_FATAL("BpManager::Get CreateFileMapping error");
  1421. }
  1422. }
  1423. else
  1424. {
  1425. BF_FATAL("BpManager::Get CreateMutex error");
  1426. }
  1427. #endif //BF_PLATFORM_WINDOWS
  1428. if (sBpManager == NULL)
  1429. {
  1430. sBpManager = new BpManager();
  1431. gBpManagerOwner.mOwnedManager = sBpManager;
  1432. }
  1433. return sBpManager;
  1434. }
  1435. //////////////////////////////////////////////////////////////////////////
  1436. BP_EXPORT void BP_CALLTYPE BpShutdown()
  1437. {
  1438. BpManager::Get()->Shutdown();
  1439. }
  1440. BP_EXPORT void BP_CALLTYPE BpSetClientName(const char* clientName)
  1441. {
  1442. BpManager::Get()->SetClientName(clientName);
  1443. }
  1444. BP_EXPORT void BP_CALLTYPE BpInit(const char* serverName, const char* sessionName)
  1445. {
  1446. BpManager::Get()->Init(serverName, sessionName);
  1447. }
  1448. BP_EXPORT BpConnectState BP_CALLTYPE BpGetConnectState()
  1449. {
  1450. return BpManager::Get()->mConnectState;
  1451. }
  1452. BP_EXPORT void BP_CALLTYPE BpRetryConnect()
  1453. {
  1454. return BpManager::Get()->RetryConnect();
  1455. }
  1456. BP_EXPORT void BP_CALLTYPE BpPause()
  1457. {
  1458. BpManager::Get()->Pause();
  1459. }
  1460. BP_EXPORT void BP_CALLTYPE BpUnpause()
  1461. {
  1462. BpManager::Get()->Unpause();
  1463. }
  1464. BP_EXPORT void BP_CALLTYPE BpSetThreadName(const char* threadName)
  1465. {
  1466. BpManager::GetCurThreadInfo()->SetThreadName(threadName);
  1467. }
  1468. BP_EXPORT void BP_CALLTYPE BpEnter(const char* zoneName)
  1469. {
  1470. BpManager::GetCurThreadInfo()->Enter(zoneName);
  1471. }
  1472. BP_EXPORT void BP_CALLTYPE BpEnterF(const char* zoneName, ...)
  1473. {
  1474. va_list args;
  1475. va_start(args, zoneName);
  1476. BpManager::GetCurThreadInfo()->Enter(zoneName, args);
  1477. }
  1478. BP_EXPORT void BP_CALLTYPE BpLeave()
  1479. {
  1480. BpManager::GetCurThreadInfo()->Leave();
  1481. }
  1482. BP_EXPORT void BP_CALLTYPE BpFrameTick()
  1483. {
  1484. BpManager::Get()->Tick();
  1485. }
  1486. BP_EXPORT void BP_CALLTYPE BpEvent(const char* name, const char* details)
  1487. {
  1488. BpManager::GetCurThreadInfo()->Event(name, details);
  1489. }
  1490. BP_EXPORT const char* BP_CALLTYPE BpDynStr(const char* str)
  1491. {
  1492. return BpManager::GetCurThreadInfo()->DynamicString(str);
  1493. }
  1494. #else
  1495. BP_EXPORT void BP_CALLTYPE BpShutdown()
  1496. {
  1497. }
  1498. BP_EXPORT BpConnectState BP_CALLTYPE BpGetConnectState()
  1499. {
  1500. return BpConnectState_NotConnected;
  1501. }
  1502. BP_EXPORT void BP_CALLTYPE BpRetryConnect()
  1503. {
  1504. }
  1505. BP_EXPORT void BP_CALLTYPE BpPause()
  1506. {
  1507. }
  1508. BP_EXPORT void BP_CALLTYPE BpUnpause()
  1509. {
  1510. }
  1511. BP_EXPORT void BP_CALLTYPE BpSetClientName(const char* clientName)
  1512. {
  1513. }
  1514. BP_EXPORT void BP_CALLTYPE BpInit(const char* serverName, const char* sessionName)
  1515. {
  1516. }
  1517. BP_EXPORT void BP_CALLTYPE BpSetThreadName(const char* threadName)
  1518. {
  1519. }
  1520. BP_EXPORT void BP_CALLTYPE BpEnter(const char* zoneName)
  1521. {
  1522. }
  1523. BP_EXPORT void BP_CALLTYPE BpEnterF(const char* zoneName, ...)
  1524. {
  1525. }
  1526. BP_EXPORT void BP_CALLTYPE BpLeave()
  1527. {
  1528. }
  1529. BP_EXPORT void BP_CALLTYPE BpFrameTick()
  1530. {
  1531. }
  1532. BP_EXPORT void BP_CALLTYPE BpEvent(const char* name, const char* details)
  1533. {
  1534. }
  1535. BP_EXPORT const char* BP_CALLTYPE BpDynStr(const char* str)
  1536. {
  1537. return str;
  1538. }
  1539. #endif