Skip to content

Commit 4b77aff

Browse files
Add CPU masking/pinning option
Add an option to specify which CPU cores the replayer is able to use. Change-Id: I1ff25355dbcc1da34830b8926dc5eb7078889ec5
1 parent 8e66328 commit 4b77aff

File tree

8 files changed

+154
-6
lines changed

8 files changed

+154
-6
lines changed

USAGE_android.md

+9-2
Original file line numberDiff line numberDiff line change
@@ -700,7 +700,7 @@ queryable permission to apply.
700700
The `gfxrecon.py replay` command has the following usage:
701701

702702
```text
703-
usage: gfxrecon.py replay [-h] [--push-file LOCAL_FILE] [--version] [--pause-frame N]
703+
usage: gfxrecon.py replay [-h] [--push-file LOCAL_FILE] [--version] [--cpu-mask <binary-mask>] [--pause-frame N]
704704
[--paused] [--screenshot-all] [--screenshots RANGES]
705705
[--screenshot-format FORMAT] [--screenshot-dir DIR]
706706
[--screenshot-prefix PREFIX] [--screenshot-scale SCALE]
@@ -749,6 +749,13 @@ optional arguments:
749749
-p LOCAL_FILE, --push-file LOCAL_FILE
750750
Local file to push to the location on device specified
751751
by <file>
752+
--cpu-mask <binary-mask>
753+
Set of CPU cores used by the replayer.
754+
`binary-mask` is a succession of '0' and '1' that specifies
755+
used/unused cores. For example '1010' activates the first and
756+
third cores and deactivate all other cores.
757+
If the option is not set, all cores can be used. If the option
758+
is set only for some cores, the other cores are not used.
752759
--screenshot-all Generate screenshots for all frames. When this option
753760
is specified, --screenshots is ignored (forwarded to
754761
replay tool)
@@ -792,7 +799,7 @@ optional arguments:
792799
See gfxrecon-extract.
793800
--opcd, --omit-pipeline-cache-data
794801
Omit pipeline cache data from calls to
795-
vkCreatePipelineCache and skip calls to
802+
vkCreatePipelineCache and skip calls to--cpu-mask <binary-mask>
796803
vkGetPipelineCacheData (forwarded to replay tool)
797804
--surface-index N Restrict rendering to the Nth surface object created.
798805
Used with captures that include multiple surfaces.

USAGE_desktop_D3D12.md

+8-1
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ The `gfxrecon-replay` tool accepts the following command line arguments:
197197
gfxrecon-replay.exe - A tool to replay GFXReconstruct capture files.
198198
199199
Usage:
200-
gfxrecon-replay.exe [-h | --help] [--version] [--gpu <index>]
200+
gfxrecon-replay.exe [-h | --help] [--version] [--cpu-mask <binary-mask>] [--gpu <index>]
201201
[--pause-frame <N>] [--paused] [--sync] [--screenshot-all]
202202
[--screenshots <N1(-N2),...>] [--screenshot-format <format>]
203203
[--screenshot-dir <dir>] [--screenshot-prefix <file-prefix>]
@@ -268,6 +268,13 @@ Optional arguments:
268268
--validate Enables the Khronos Vulkan validation layer when replaying a
269269
Vulkan capture or the Direct3D debug layer when replaying a
270270
Direct3D 12 capture.
271+
--cpu-mask <binary-mask>
272+
Set of CPU cores used by the replayer.
273+
`binary-mask` is a succession of '0' and '1' that specifies
274+
used/unused cores. For example '1010' activates the first and
275+
third cores and deactivate all other cores.
276+
If the option is not set, all cores can be used. If the option
277+
is set only for some cores, the other cores are not used.
271278
--gpu <index> Use the specified device for replay, where index
272279
is the zero-based index to the array of physical devices
273280
returned by vkEnumeratePhysicalDevices or IDXGIFactory1::EnumAdapters1.

USAGE_desktop_Vulkan.md

+8-1
Original file line numberDiff line numberDiff line change
@@ -546,7 +546,7 @@ The `gfxrecon-replay` tool for desktop accepts the following command line
546546
arguments:
547547

548548
```text
549-
gfxrecon-replay [-h | --help] [--version] [--gpu <index>]
549+
gfxrecon-replay [-h | --help] [--version] [--cpu-mask <binary-mask>] [--gpu <index>]
550550
[--pause-frame <N>] [--paused] [--sync] [--screenshot-all]
551551
[--screenshots <N1(-N2),...>] [--screenshot-format <format>]
552552
[--screenshot-dir <dir>] [--screenshot-prefix <file-prefix>]
@@ -587,6 +587,13 @@ Optional arguments:
587587
--log-file <file> Write log messages to a file at the specified path.
588588
Default is: Empty string (file logging disabled).
589589
--log-debugview Log messages with OutputDebugStringA. Windows only.
590+
--cpu-mask <binary-mask>
591+
Set of CPU cores used by the replayer.
592+
`binary-mask` is a succession of '0' and '1' that specifies
593+
used/unused cores. For example '1010' activates the first and
594+
third cores and deactivate all other cores.
595+
If the option is not set, all cores can be used. If the option
596+
is set only for some cores, the other cores are not used.
590597
--gpu <index> Use the specified device for replay, where index
591598
is the zero-based index to the array of physical devices
592599
returned by vkEnumeratePhysicalDevices. Replay may fail

android/scripts/gfxrecon.py

+5
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ def CreateReplayParser():
7171
parser.add_argument('--log-file', metavar='DEVICE_FILE', help='Write log messages to a file at the specified path instead of logcat (forwarded to replay tool)')
7272
parser.add_argument('--pause-frame', metavar='N', help='Pause after replaying frame number N (forwarded to replay tool)')
7373
parser.add_argument('--paused', action='store_true', default=False, help='Pause after replaying the first frame (same as "--pause-frame 1"; forwarded to replay tool)')
74+
parser.add_argument('--cpu-mask', metavar='binary_mask', help='Set of CPU cores used by the replayer. `binary-mask` is a succession of "0" and "1" that specifies used/unused cores. For example "1010" activates the first and third cores and deactivate all other cores. If the option is not set, all cores can be used. If the option is set only for some cores, the other cores are not used. (forwarded to replay tool)')
7475
parser.add_argument('--screenshot-all', action='store_true', default=False, help='Generate screenshots for all frames. When this option is specified, --screenshots is ignored (forwarded to replay tool)')
7576
parser.add_argument('--screenshots', metavar='RANGES', help='Generate screenshots for the specified frames. Target frames are specified as a comma separated list of frame ranges. A frame range can be specified as a single value, to specify a single frame, or as two hyphenated values, to specify the first and last frames to process. Frame ranges should be specified in ascending order and cannot overlap. Note that frame numbering is 1-based (i.e. the first frame is frame 1). Example: 200,301-305 will generate six screenshots (forwarded to replay tool)')
7677
parser.add_argument('--screenshot-format', metavar='FORMAT', choices=['bmp', 'png'], help='Image file format to use for screenshot generation. Available formats are: bmp, png (forwarded to replay tool)')
@@ -142,6 +143,10 @@ def MakeExtrasString(args):
142143
if args.paused:
143144
arg_list.append('--paused')
144145

146+
if args.cpu_mask:
147+
arg_list.append('--cpu-mask')
148+
arg_list.append('{}'.format(args.cpu_mask))
149+
145150
if args.screenshot_all:
146151
arg_list.append('--screenshot-all')
147152
elif args.screenshots:

framework/decode/replay_options.h

+1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ struct ReplayOptions
5555
bool force_windowed_origin{ false };
5656
int32_t window_topleft_x{ 0 };
5757
int32_t window_topleft_y{ 0 };
58+
std::string cpu_mask;
5859
int32_t override_gpu_index{ -1 };
5960
std::string capture_filename;
6061
bool enable_print_block_info{ false };

framework/util/platform.h

+98
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@
5757
#include <sys/system_properties.h>
5858
#endif
5959

60+
#ifdef __linux__
61+
#include <sched.h>
62+
#endif
63+
6064
GFXRECON_BEGIN_NAMESPACE(gfxrecon)
6165
GFXRECON_BEGIN_NAMESPACE(util)
6266
GFXRECON_BEGIN_NAMESPACE(platform)
@@ -260,6 +264,52 @@ inline int GetSystemLastErrorCode()
260264
return GetLastError();
261265
}
262266

267+
inline std::string GetCpuAffinity()
268+
{
269+
DWORD_PTR process_mask;
270+
DWORD_PTR system_mask;
271+
if (!GetProcessAffinityMask(GetCurrentProcess(), &process_mask, &system_mask))
272+
{
273+
return "";
274+
}
275+
276+
DWORD_PTR mask = (process_mask & system_mask);
277+
278+
std::string affinity;
279+
while (mask)
280+
{
281+
affinity += (mask & 1) ? "1" : "0";
282+
mask >>= 1;
283+
}
284+
285+
while (affinity.back() == '0')
286+
{
287+
affinity.pop_back();
288+
}
289+
290+
return affinity;
291+
}
292+
293+
inline bool SetCpuAffinity(const std::string& affinity)
294+
{
295+
DWORD_PTR mask = 0;
296+
for (unsigned i = 0; i < affinity.size(); i++)
297+
{
298+
if (affinity[i] == '1')
299+
{
300+
mask |= 1;
301+
}
302+
else if (affinity[i] != '0')
303+
{
304+
return false;
305+
}
306+
307+
mask <<= 1;
308+
}
309+
310+
return (SetProcessAffinityMask(GetCurrentProcess(), mask) != 0);
311+
}
312+
263313
#else // !defined(WIN32)
264314

265315
// Error value indicating string was truncated
@@ -568,6 +618,54 @@ inline int GetSystemLastErrorCode()
568618
return errno;
569619
}
570620

621+
inline std::string GetCpuAffinity()
622+
{
623+
std::string affinity;
624+
625+
#ifdef __linux__
626+
cpu_set_t mask;
627+
if (sched_getaffinity(0, sizeof(mask), &mask))
628+
{
629+
return affinity;
630+
}
631+
632+
for (unsigned i = 0; i < sizeof(mask) / CPU_ALLOC_SIZE(1); i++)
633+
{
634+
affinity += CPU_ISSET(i, &mask) ? "1" : "0";
635+
}
636+
637+
while (affinity.back() == '0')
638+
{
639+
affinity.pop_back();
640+
}
641+
#endif
642+
643+
return affinity;
644+
}
645+
646+
static bool SetCpuAffinity(const std::string& affinity)
647+
{
648+
#ifdef __linux__
649+
cpu_set_t mask;
650+
CPU_ZERO(&mask);
651+
for (unsigned i = 0; i < affinity.size(); i++)
652+
{
653+
if (affinity[i] == '1')
654+
{
655+
CPU_SET(i, &mask);
656+
}
657+
else if (affinity[i] != '0')
658+
{
659+
return false;
660+
}
661+
}
662+
663+
return (sched_setaffinity(0, sizeof(mask), &mask) == 0);
664+
#else
665+
return false;
666+
#endif
667+
}
668+
571669
#endif // WIN32
572670

573671
inline size_t GetAlignedSize(size_t size, size_t align_to)

tools/replay/replay_settings.h

+10-2
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ const char kOptions[] =
3838
"resources,--dump-resources-dump-all-image-subresources,--dump-resources-dump-raw-images,--dump-resources-dump-"
3939
"separate-alpha,--pbi-all,--preload-measurement-range, --add-new-pipeline-caches";
4040
const char kArguments[] =
41-
"--log-level,--log-file,--gpu,--gpu-group,--pause-frame,--wsi,--surface-index,-m|--memory-translation,"
41+
"--log-level,--log-file,--cpu-mask,--gpu,--gpu-group,--pause-frame,--wsi,--surface-index,-m|--memory-translation,"
4242
"--replace-shaders,--screenshots,--denied-messages,--allowed-messages,--screenshot-format,--"
4343
"screenshot-dir,--screenshot-prefix,--screenshot-size,--screenshot-scale,--mfr|--measurement-frame-range,--fw|--"
4444
"force-windowed,--fwo|--force-windowed-origin,--batching-memory-usage,--measurement-file,--swapchain,--sgfs|--skip-"
@@ -59,7 +59,8 @@ static void PrintUsage(const char* exe_name)
5959

6060
GFXRECON_WRITE_CONSOLE("\n%s - A tool to replay GFXReconstruct capture files.\n", app_name.c_str());
6161
GFXRECON_WRITE_CONSOLE("Usage:");
62-
GFXRECON_WRITE_CONSOLE(" %s\t[-h | --help] [--version] [--gpu <index>] [--gpu-group <index>]", app_name.c_str());
62+
GFXRECON_WRITE_CONSOLE(" %s\t[-h | --help] [--version]", app_name.c_str());
63+
GFXRECON_WRITE_CONSOLE("\t\t\t[--cpu-mask <binary-mask>] [--gpu <index>] [--gpu-group <index>]");
6364
GFXRECON_WRITE_CONSOLE("\t\t\t[--pause-frame <N>] [--paused] [--sync] [--screenshot-all]");
6465
GFXRECON_WRITE_CONSOLE("\t\t\t[--screenshots <N1(-N2),...>] [--screenshot-format <format>]");
6566
GFXRECON_WRITE_CONSOLE("\t\t\t[--screenshot-dir <dir>] [--screenshot-prefix <file-prefix>]");
@@ -159,6 +160,13 @@ static void PrintUsage(const char* exe_name)
159160
GFXRECON_WRITE_CONSOLE(" --validate\t\tEnable the Khronos Vulkan validation layer when replaying a");
160161
GFXRECON_WRITE_CONSOLE(" \t\tVulkan capture or the Direct3D debug layer when replaying a");
161162
GFXRECON_WRITE_CONSOLE(" \t\tDirect3D 12 capture.");
163+
GFXRECON_WRITE_CONSOLE(" --cpu-mask <binary-mask>");
164+
GFXRECON_WRITE_CONSOLE(" \t\tSet of CPU cores used by the replayer.");
165+
GFXRECON_WRITE_CONSOLE(" \t\t`binary-mask` is a succession of '0' and '1' that specifies");
166+
GFXRECON_WRITE_CONSOLE(" \t\tused/unused cores. For example '1010' activates the first and");
167+
GFXRECON_WRITE_CONSOLE(" \t\tthird cores and deactivate all other cores.");
168+
GFXRECON_WRITE_CONSOLE(" \t\tIf the option is not set, all cores can be used. If the option");
169+
GFXRECON_WRITE_CONSOLE(" \t\tis set only for some cores, the other cores are not used.");
162170
GFXRECON_WRITE_CONSOLE(" --gpu <index>\t\tUse the specified device for replay, where index");
163171
GFXRECON_WRITE_CONSOLE(" \t\tis the zero-based index to the array of physical devices");
164172
GFXRECON_WRITE_CONSOLE(" \t\treturned by vkEnumeratePhysicalDevices or IDXGIFactory1::EnumAdapters1.");

tools/tool_settings.h

+15
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ const char kLogLevelArgument[] = "--log-level";
6464
const char kLogFileArgument[] = "--log-file";
6565
const char kLogDebugView[] = "--log-debugview";
6666
const char kNoDebugPopup[] = "--no-debug-popup";
67+
const char kCpuMaskArgument[] = "--cpu-mask";
6768
const char kOverrideGpuArgument[] = "--gpu";
6869
const char kOverrideGpuGroupArgument[] = "--gpu-group";
6970
const char kPausedOption[] = "--paused";
@@ -934,6 +935,20 @@ static void GetReplayOptions(gfxrecon::decode::ReplayOptions& options,
934935
options.num_pipeline_creation_jobs = std::stoi(arg_parser.GetArgumentValue(kNumPipelineCreationJobs));
935936
}
936937

938+
options.cpu_mask = arg_parser.GetArgumentValue(kCpuMaskArgument);
939+
if (!options.cpu_mask.empty())
940+
{
941+
if (gfxrecon::util::platform::SetCpuAffinity(options.cpu_mask))
942+
{
943+
GFXRECON_LOG_INFO("CPU mask successfully set: %s", gfxrecon::util::platform::GetCpuAffinity().c_str());
944+
}
945+
else
946+
{
947+
GFXRECON_LOG_ERROR("Failed to set CPU mask: %s", options.cpu_mask.c_str());
948+
GFXRECON_LOG_ERROR("Resuming with CPU mask: %s", gfxrecon::util::platform::GetCpuAffinity().c_str());
949+
}
950+
}
951+
937952
const auto& override_gpu = arg_parser.GetArgumentValue(kOverrideGpuArgument);
938953
if (!override_gpu.empty())
939954
{

0 commit comments

Comments
 (0)