// for user convenience, bundle all logs into this file: void psBundleLogs(FILE* f) { fwprintf(f, L"SVN Revision: %ls\n\n", svn_revision); fwprintf(f, L"Engine Version: %hs\n\n", engine_version); fwprintf(f, L"System info:\n\n"); OsPath path1 = psLogDir()/"system_info.txt"; AppendAsciiFile(f, path1); fwprintf(f, L"\n\n====================================\n\n"); fwprintf(f, L"Main log:\n\n"); OsPath path2 = psLogDir()/"mainlog.html"; AppendAsciiFile(f, path2); fwprintf(f, L"\n\n====================================\n\n"); }
void CProfileViewer::SaveToFile() { // Open the file, if necessary. If this method is called several times, // the profile results will be appended to the previous ones from the same // run. if (! m->outputStream.is_open()) { // Open the file. (It will be closed when the CProfileViewer // destructor is called.) OsPath path = psLogDir()/"profile.txt"; m->outputStream.open(OsString(path).c_str(), std::ofstream::out | std::ofstream::trunc); if (m->outputStream.fail()) { LOGERROR(L"Failed to open profile log file"); return; } else { LOGMESSAGERENDER(L"Profiler snapshot saved to '%ls'", path.string().c_str()); } } time_t t; time(&t); m->outputStream << "================================================================\n\n"; m->outputStream << "PS profiler snapshot - " << asctime(localtime(&t)); std::vector<AbstractProfileTable*> tables = m->rootTables; sort(tables.begin(), tables.end(), SortByName); for_each(tables.begin(), tables.end(), WriteTable(m->outputStream)); m->outputStream << "\n\n================================================================\n"; m->outputStream.flush(); }
void CNetTurnManager::OnSyncError(u32 turn, const std::string& expectedHash) { NETTURN_LOG((L"OnSyncError(%d, %ls)\n", turn, Hexify(expectedHash).c_str())); // Only complain the first time if (m_HasSyncError) return; m_HasSyncError = true; bool quick = !TurnNeedsFullHash(turn); std::string hash; bool ok = m_Simulation2.ComputeStateHash(hash, quick); ENSURE(ok); OsPath path = psLogDir()/"oos_dump.txt"; std::ofstream file (OsString(path).c_str(), std::ofstream::out | std::ofstream::trunc); m_Simulation2.DumpDebugState(file); file.close(); std::wstringstream msg; msg << L"Out of sync on turn " << turn << L": expected hash " << Hexify(expectedHash) << L"\n\n"; msg << L"Current state: turn " << m_CurrentTurn << L", hash " << Hexify(hash) << L"\n\n"; msg << L"Dumping current state to " << path; g_GUI->DisplayMessageBox(600, 350, L"Sync error", msg.str()); }
void CProfiler2::SaveToFile() { OsPath path = psLogDir()/"profile2.jsonp"; std::ofstream stream(OsString(path).c_str(), std::ofstream::out | std::ofstream::trunc); ENSURE(stream.good()); std::vector<ThreadStorage*> threads; { CScopeLock lock(m_Mutex); threads = m_Threads; } stream << "profileDataCB({\"threads\": [\n"; for (size_t i = 0; i < threads.size(); ++i) { if (i != 0) stream << ",\n"; stream << "{\"name\":\"" << CStr(threads[i]->GetName()).EscapeToPrintableASCII() << "\",\n"; stream << "\"data\": "; ConstructJSONResponse(stream, threads[i]->GetName()); stream << "\n}"; } stream << "\n]});\n"; }
void CReplayLogger::StartGame(JS::MutableHandleValue attribs) { // Add timestamp, since the file-modification-date can change m_ScriptInterface.SetProperty(attribs, "timestamp", std::to_string(std::time(nullptr))); // Add engine version and currently loaded mods for sanity checks when replaying m_ScriptInterface.SetProperty(attribs, "engine_version", CStr(engine_version)); m_ScriptInterface.SetProperty(attribs, "mods", g_modsLoaded); // Construct the directory name based on the PID, to be relatively unique. // Append "-1", "-2" etc if we run multiple matches in a single session, // to avoid accidentally overwriting earlier logs. static int run = -1; do { std::wstringstream name; name << getpid(); if (++run) name << "-" << run; m_Directory = psLogDir() / L"sim_log" / name.str(); } while (DirectoryExists(m_Directory)); CreateDirectories(m_Directory, 0700); m_Stream = new std::ofstream(OsString(m_Directory / L"commands.txt").c_str(), std::ofstream::out | std::ofstream::trunc); *m_Stream << "start " << m_ScriptInterface.StringifyJSON(attribs, false) << "\n"; }
void CSimulation2Impl::DumpState() { PROFILE("DumpState"); std::stringstream pid; pid << getpid(); std::stringstream name;\ name << std::setw(5) << std::setfill('0') << m_TurnNumber << ".txt"; OsPath path = psLogDir() / "sim_log" / pid.str() / name.str(); CreateDirectories(path.Parent(), 0700); std::ofstream file (OsString(path).c_str(), std::ofstream::out | std::ofstream::trunc); file << "State hash: " << std::hex; std::string hashRaw; m_ComponentManager.ComputeStateHash(hashRaw, false); for (size_t i = 0; i < hashRaw.size(); ++i) file << std::setfill('0') << std::setw(2) << (int)(unsigned char)hashRaw[i]; file << std::dec << "\n"; file << "\n"; m_ComponentManager.DumpDebugState(file, true); std::ofstream binfile (OsString(path.ChangeExtension(L".dat")).c_str(), std::ofstream::out | std::ofstream::trunc | std::ofstream::binary); m_ComponentManager.SerializeState(binfile); }
void CSimulation2Impl::ReportSerializationFailure( SerializationTestState* primaryStateBefore, SerializationTestState* primaryStateAfter, SerializationTestState* secondaryStateBefore, SerializationTestState* secondaryStateAfter) { OsPath path = psLogDir() / "oos_log"; CreateDirectories(path, 0700); // Clean up obsolete files from previous runs wunlink(path / "hash.before.a"); wunlink(path / "hash.before.b"); wunlink(path / "debug.before.a"); wunlink(path / "debug.before.b"); wunlink(path / "state.before.a"); wunlink(path / "state.before.b"); wunlink(path / "hash.after.a"); wunlink(path / "hash.after.b"); wunlink(path / "debug.after.a"); wunlink(path / "debug.after.b"); wunlink(path / "state.after.a"); wunlink(path / "state.after.b"); if (primaryStateBefore) DumpSerializationTestState(*primaryStateBefore, path, L"before.a"); if (primaryStateAfter) DumpSerializationTestState(*primaryStateAfter, path, L"after.a"); if (secondaryStateBefore) DumpSerializationTestState(*secondaryStateBefore, path, L"before.b"); if (secondaryStateAfter) DumpSerializationTestState(*secondaryStateAfter, path, L"after.b"); debug_warn(L"Serialization test failure"); }
void DumpHeap(const char* basename, int idx, JSContext* cx) { char filename[64]; sprintf_s(filename, ARRAY_SIZE(filename), "%s.%03d.txt", basename, idx); OsPath pathname = psLogDir() / filename; FILE* f = sys_OpenFile(pathname, "w"); ENSURE(f); JS_DumpHeap(cx, f, NULL, 0, NULL, (size_t)-1, NULL); fclose(f); }
CReplayLogger::CReplayLogger(ScriptInterface& scriptInterface) : m_ScriptInterface(scriptInterface) { // Construct the directory name based on the PID, to be relatively unique. // Append "-1", "-2" etc if we run multiple matches in a single session, // to avoid accidentally overwriting earlier logs. std::wstringstream name; name << getpid(); static int run = -1; if (++run) name << "-" << run; OsPath path = psLogDir() / L"sim_log" / name.str() / L"commands.txt"; CreateDirectories(path.Parent(), 0700); m_Stream = new std::ofstream(OsString(path).c_str(), std::ofstream::out | std::ofstream::trunc); }
void CNetTurnManager::OnSyncError(u32 turn, const CStr& expectedHash, std::vector<CSyncErrorMessage::S_m_PlayerNames>& playerNames) { NETTURN_LOG((L"OnSyncError(%d, %hs)\n", turn, Hexify(expectedHash).c_str())); // Only complain the first time if (m_HasSyncError) return; bool quick = !TurnNeedsFullHash(turn); std::string hash; ENSURE(m_Simulation2.ComputeStateHash(hash, quick)); OsPath path = psLogDir()/"oos_dump.txt"; std::ofstream file (OsString(path).c_str(), std::ofstream::out | std::ofstream::trunc); m_Simulation2.DumpDebugState(file); file.close(); hash = Hexify(hash); const std::string& expectedHashHex = Hexify(expectedHash); DisplayOOSError(turn, hash, expectedHashHex, false, &playerNames, &path); }
void WriteSystemInfo() { TIMER(L"write_sys_info"); // get_cpu_info and gfx_detect already called during init - see call site snd_detect(); struct utsname un; uname(&un); OsPath pathname = psLogDir()/"system_info.txt"; FILE* f = sys_OpenFile(pathname, "w"); if(!f) return; // current timestamp (redundant WRT OS timestamp, but that is not // visible when people are posting this file's contents online) { wchar_t timestampBuf[100] = {'\0'}; time_t seconds; time(&seconds); struct tm* t = gmtime(&seconds); const size_t charsWritten = wcsftime(timestampBuf, ARRAY_SIZE(timestampBuf), L"(generated %Y-%m-%d %H:%M:%S UTC)", t); ENSURE(charsWritten != 0); fprintf(f, "%ls\n\n", timestampBuf); } // OS fprintf(f, "OS : %s %s (%s)\n", un.sysname, un.release, un.version); // CPU fprintf(f, "CPU : %s, %s", un.machine, cpu_IdentifierString()); #if ARCH_X86_X64 fprintf(f, " (%dx%dx%d)", (int)topology::NumPackages(), (int)topology::CoresPerPackage(), (int)topology::LogicalPerCore()); #endif double cpuClock = os_cpu_ClockFrequency(); // query OS (may fail) #if ARCH_X86_X64 if(cpuClock <= 0.0) cpuClock = x86_x64::ClockFrequency(); // measure (takes a few ms) #endif if(cpuClock > 0.0) { if(cpuClock < 1e9) fprintf(f, ", %.2f MHz\n", cpuClock*1e-6); else fprintf(f, ", %.2f GHz\n", cpuClock*1e-9); } else fprintf(f, "\n"); // memory fprintf(f, "Memory : %u MiB; %u MiB free\n", (unsigned)os_cpu_MemorySize(), (unsigned)os_cpu_MemoryAvailable()); // graphics const std::wstring cardName = gfx::CardName(); const std::wstring driverInfo = gfx::DriverInfo(); fprintf(f, "Graphics Card : %ls\n", cardName.c_str()); fprintf(f, "OpenGL Drivers : %s; %ls\n", glGetString(GL_VERSION), driverInfo.c_str()); fprintf(f, "Video Mode : %dx%d:%d\n", g_VideoMode.GetXRes(), g_VideoMode.GetYRes(), g_VideoMode.GetBPP()); // sound fprintf(f, "Sound Card : %ls\n", snd_card); fprintf(f, "Sound Drivers : %ls\n", snd_drv_ver); // OpenGL extensions (write them last, since it's a lot of text) const char* exts = ogl_ExtensionString(); if (!exts) exts = "{unknown}"; fprintf(f, "\nOpenGL Extensions: \n%s\n", SplitExts(exts).c_str()); // System Management BIOS (even more text than OpenGL extensions) std::string smbios = SMBIOS::StringizeStructures(SMBIOS::GetStructures()); fprintf(f, "\nSMBIOS: \n%s\n", smbios.c_str()); fclose(f); f = 0; }