|
33 | 33 | #include "ai/ai.hpp"
|
34 | 34 | #include "ai/ai_config.hpp"
|
35 | 35 | #include "newgrf.h"
|
| 36 | +#include "newgrf_profiling.h" |
36 | 37 | #include "console_func.h"
|
37 | 38 | #include "engine_base.h"
|
38 | 39 | #include "game/game.hpp"
|
@@ -1877,6 +1878,135 @@ DEF_CONSOLE_CMD(ConNewGRFReload)
|
1877 | 1878 | return true;
|
1878 | 1879 | }
|
1879 | 1880 |
|
| 1881 | +DEF_CONSOLE_CMD(ConNewGRFProfile) |
| 1882 | +{ |
| 1883 | + if (argc == 0) { |
| 1884 | + IConsoleHelp("Collect performance data about NewGRF sprite requests and callbacks. Sub-commands can be abbreviated."); |
| 1885 | + IConsoleHelp("Usage: newgrf_profile [list]"); |
| 1886 | + IConsoleHelp(" List all NewGRFs that can be profiled, and their status."); |
| 1887 | + IConsoleHelp("Usage: newgrf_profile select <grf-num>..."); |
| 1888 | + IConsoleHelp(" Select one or more GRFs for profiling."); |
| 1889 | + IConsoleHelp("Usage: newgrf_profile unselect <grf-num>..."); |
| 1890 | + IConsoleHelp(" Unselect one or more GRFs from profiling. Use the keyword \"all\" instead of a GRF number to unselect all. Removing an active profiler aborts data collection."); |
| 1891 | + IConsoleHelp("Usage: newgrf_profile start [<num-days>]"); |
| 1892 | + IConsoleHelp(" Begin profiling all selected GRFs. If a number of days is provided, profiling stops after that many in-game days."); |
| 1893 | + IConsoleHelp("Usage: newgrf_profile stop"); |
| 1894 | + IConsoleHelp(" End profiling and write the collected data to CSV files."); |
| 1895 | + IConsoleHelp("Usage: newgrf_profile abort"); |
| 1896 | + IConsoleHelp(" End profiling and discard all collected data."); |
| 1897 | + return true; |
| 1898 | + } |
| 1899 | + |
| 1900 | + extern const std::vector<GRFFile *> &GetAllGRFFiles(); |
| 1901 | + const std::vector<GRFFile *> &files = GetAllGRFFiles(); |
| 1902 | + |
| 1903 | + /* "list" sub-command */ |
| 1904 | + if (argc == 1 || strncasecmp(argv[1], "lis", 3) == 0) { |
| 1905 | + IConsolePrint(CC_INFO, "Loaded GRF files:"); |
| 1906 | + int i = 1; |
| 1907 | + for (GRFFile *grf : files) { |
| 1908 | + auto profiler = std::find_if(_newgrf_profilers.begin(), _newgrf_profilers.end(), [&](NewGRFProfiler &pr) { return pr.grffile == grf; }); |
| 1909 | + bool selected = profiler != _newgrf_profilers.end(); |
| 1910 | + bool active = selected && profiler->active; |
| 1911 | + TextColour tc = active ? TC_LIGHT_BLUE : selected ? TC_GREEN : CC_INFO; |
| 1912 | + const char *statustext = active ? " (active)" : selected ? " (selected)" : ""; |
| 1913 | + IConsolePrintF(tc, "%d: [%08X] %s%s", i, BSWAP32(grf->grfid), grf->filename, statustext); |
| 1914 | + i++; |
| 1915 | + } |
| 1916 | + return true; |
| 1917 | + } |
| 1918 | + |
| 1919 | + /* "select" sub-command */ |
| 1920 | + if (strncasecmp(argv[1], "sel", 3) == 0 && argc >= 3) { |
| 1921 | + for (size_t argnum = 2; argnum < argc; ++argnum) { |
| 1922 | + int grfnum = atoi(argv[argnum]); |
| 1923 | + if (grfnum < 1 || grfnum > (int)files.size()) { // safe cast, files.size() should not be larger than a few hundred in the most extreme cases |
| 1924 | + IConsolePrintF(CC_WARNING, "GRF number %d out of range, not added.", grfnum); |
| 1925 | + continue; |
| 1926 | + } |
| 1927 | + GRFFile *grf = files[grfnum - 1]; |
| 1928 | + if (std::any_of(_newgrf_profilers.begin(), _newgrf_profilers.end(), [&](NewGRFProfiler &pr) { return pr.grffile == grf; })) { |
| 1929 | + IConsolePrintF(CC_WARNING, "GRF number %d [%08X] is already selected for profiling.", grfnum, BSWAP32(grf->grfid)); |
| 1930 | + continue; |
| 1931 | + } |
| 1932 | + _newgrf_profilers.emplace_back(grf); |
| 1933 | + } |
| 1934 | + return true; |
| 1935 | + } |
| 1936 | + |
| 1937 | + /* "unselect" sub-command */ |
| 1938 | + if (strncasecmp(argv[1], "uns", 3) == 0 && argc >= 3) { |
| 1939 | + for (size_t argnum = 2; argnum < argc; ++argnum) { |
| 1940 | + if (strcasecmp(argv[argnum], "all") == 0) { |
| 1941 | + _newgrf_profilers.clear(); |
| 1942 | + break; |
| 1943 | + } |
| 1944 | + int grfnum = atoi(argv[argnum]); |
| 1945 | + if (grfnum < 1 || grfnum > (int)files.size()) { |
| 1946 | + IConsolePrintF(CC_WARNING, "GRF number %d out of range, not removing.", grfnum); |
| 1947 | + continue; |
| 1948 | + } |
| 1949 | + GRFFile *grf = files[grfnum - 1]; |
| 1950 | + auto pos = std::find_if(_newgrf_profilers.begin(), _newgrf_profilers.end(), [&](NewGRFProfiler &pr) { return pr.grffile == grf; }); |
| 1951 | + if (pos != _newgrf_profilers.end()) _newgrf_profilers.erase(pos); |
| 1952 | + } |
| 1953 | + return true; |
| 1954 | + } |
| 1955 | + |
| 1956 | + /* "start" sub-command */ |
| 1957 | + if (strncasecmp(argv[1], "sta", 3) == 0) { |
| 1958 | + std::string grfids; |
| 1959 | + size_t started = 0; |
| 1960 | + for (NewGRFProfiler &pr : _newgrf_profilers) { |
| 1961 | + if (!pr.active) { |
| 1962 | + pr.Start(); |
| 1963 | + started++; |
| 1964 | + |
| 1965 | + if (!grfids.empty()) grfids += ", "; |
| 1966 | + char grfidstr[12]{ 0 }; |
| 1967 | + seprintf(grfidstr, lastof(grfidstr), "[%08X]", BSWAP32(pr.grffile->grfid)); |
| 1968 | + grfids += grfidstr; |
| 1969 | + } |
| 1970 | + } |
| 1971 | + if (started > 0) { |
| 1972 | + IConsolePrintF(CC_DEBUG, "Started profiling for GRFID%s %s", (started > 1) ? "s" : "", grfids.c_str()); |
| 1973 | + if (argc >= 3) { |
| 1974 | + int days = max(atoi(argv[2]), 1); |
| 1975 | + _newgrf_profile_end_date = _date + days; |
| 1976 | + |
| 1977 | + char datestrbuf[32]{ 0 }; |
| 1978 | + SetDParam(0, _newgrf_profile_end_date); |
| 1979 | + GetString(datestrbuf, STR_JUST_DATE_ISO, lastof(datestrbuf)); |
| 1980 | + IConsolePrintF(CC_DEBUG, "Profiling will automatically stop on game date %s", datestrbuf); |
| 1981 | + } else { |
| 1982 | + _newgrf_profile_end_date = MAX_DAY; |
| 1983 | + } |
| 1984 | + } else if (_newgrf_profilers.empty()) { |
| 1985 | + IConsolePrintF(CC_WARNING, "No GRFs selected for profiling, did not start."); |
| 1986 | + } else { |
| 1987 | + IConsolePrintF(CC_WARNING, "Did not start profiling for any GRFs, all selected GRFs are already profiling."); |
| 1988 | + } |
| 1989 | + return true; |
| 1990 | + } |
| 1991 | + |
| 1992 | + /* "stop" sub-command */ |
| 1993 | + if (strncasecmp(argv[1], "sto", 3) == 0) { |
| 1994 | + NewGRFProfiler::FinishAll(); |
| 1995 | + return true; |
| 1996 | + } |
| 1997 | + |
| 1998 | + /* "abort" sub-command */ |
| 1999 | + if (strncasecmp(argv[1], "abo", 3) == 0) { |
| 2000 | + for (NewGRFProfiler &pr : _newgrf_profilers) { |
| 2001 | + pr.Abort(); |
| 2002 | + } |
| 2003 | + _newgrf_profile_end_date = MAX_DAY; |
| 2004 | + return true; |
| 2005 | + } |
| 2006 | + |
| 2007 | + return false; |
| 2008 | +} |
| 2009 | + |
1880 | 2010 | #ifdef _DEBUG
|
1881 | 2011 | /******************
|
1882 | 2012 | * debug commands
|
@@ -2056,4 +2186,5 @@ void IConsoleStdLibRegister()
|
2056 | 2186 |
|
2057 | 2187 | /* NewGRF development stuff */
|
2058 | 2188 | IConsoleCmdRegister("reload_newgrfs", ConNewGRFReload, ConHookNewGRFDeveloperTool);
|
| 2189 | + IConsoleCmdRegister("newgrf_profile", ConNewGRFProfile, ConHookNewGRFDeveloperTool); |
2059 | 2190 | }
|
0 commit comments