GCC Code Coverage Report


Directory: src/
File: src/talp/talp_gpu.c
Date: 2026-06-18 09:22:34
Exec Total Coverage
Lines: 5 60 8.3%
Functions: 1 6 16.7%
Branches: 1 36 2.8%

Line Branch Exec Source
1 /*********************************************************************************/
2 /* Copyright 2009-2026 Barcelona Supercomputing Center */
3 /* */
4 /* This file is part of the DLB library. */
5 /* */
6 /* DLB is free software: you can redistribute it and/or modify */
7 /* it under the terms of the GNU Lesser General Public License as published by */
8 /* the Free Software Foundation, either version 3 of the License, or */
9 /* (at your option) any later version. */
10 /* */
11 /* DLB is distributed in the hope that it will be useful, */
12 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
13 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
14 /* GNU Lesser General Public License for more details. */
15 /* */
16 /* You should have received a copy of the GNU Lesser General Public License */
17 /* along with DLB. If not, see <https://www.gnu.org/licenses/>. */
18 /*********************************************************************************/
19
20 #include "talp/talp_gpu.h"
21
22 #include "apis/dlb_errors.h"
23 #include "LB_core/spd.h"
24 #include "support/atomic.h"
25 #include "support/debug.h"
26 #include "support/dlb_common.h"
27 #include "talp/backend.h"
28 #include "talp/backend_manager.h"
29 #include "talp/regions.h"
30 #include "talp/sample.h"
31 #include "talp/talp.h"
32 #include "talp/talp_output.h"
33 #include "talp/talp_types.h"
34
35
36 extern __thread bool thread_is_observer;
37 extern __thread bool thread_is_known;
38
39 static const backend_api_t *gpu_backend_api = NULL;
40 static gpu_measurements_t gpu_sample = {0};
41
42 // Called from talp core
43 15 int talp_gpu_init(const subprocess_descriptor_t *spd) {
44
45 15 gpu_backend_api = talp_backend_manager_load_gpu_backend(spd->options.talp_gpu_backend);
46
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 if (gpu_backend_api == NULL) {
47 15 debug_warning("GPU backend could not be loaded");
48 15 return DLB_ERR_UNKNOWN;
49 }
50
51 int error;
52
53 /* If GPU component is not explicitly set, probe plugin first */
54 if (!(spd->options.talp & TALP_COMPONENT_GPU)) {
55 error = gpu_backend_api->probe();
56 if (error == DLB_BACKEND_ERROR) {
57 debug_warning("HWC backend probe failed");
58 return DLB_ERR_UNKNOWN;
59 }
60 }
61
62 error = gpu_backend_api->init(&core_api);
63 if (error == DLB_BACKEND_ERROR) {
64 debug_warning("GPU backend could not be initialized");
65 return DLB_ERR_UNKNOWN;
66 }
67
68 error = gpu_backend_api->start();
69 if (error == DLB_BACKEND_ERROR) {
70 debug_warning("GPU backend could not be started");
71 gpu_backend_api->finalize();
72 return DLB_ERR_UNKNOWN;
73 }
74
75 if (gpu_backend_api->capabilities.gpu_amd) {
76 talp_output_record_gpu_vendor(GPU_VENDOR_AMD);
77 } else if (gpu_backend_api->capabilities.gpu_nvidia) {
78 talp_output_record_gpu_vendor(GPU_VENDOR_NVIDIA);
79 }
80
81 return DLB_SUCCESS;
82 }
83
84
85 // Called from talp core
86 void talp_gpu_finalize(void) {
87
88 if (gpu_backend_api != NULL) {
89
90 gpu_backend_api->stop();
91 gpu_backend_api->flush();
92 gpu_backend_api->finalize();
93
94 talp_backend_manager_unload_gpu_backend();
95 gpu_backend_api = NULL;
96 }
97 }
98
99
100 // Called from GPU backend plugin: CPU enters GPU runtime
101 void talp_gpu_enter_runtime(void) {
102
103 /* Observer and unknown threads may call GPU offload functions, but TALP must ignore them */
104 if (unlikely(thread_is_observer || !thread_is_known)) return;
105
106 spd_enter_dlb(thread_spd);
107 talp_info_t *talp_info = thread_spd->talp_info;
108 if (talp_info) {
109 /* Update sample */
110 talp_sample_update(talp_info);
111
112 /* Into Sync call -> not_useful_gpu */
113 talp_sample_set_state(talp_info, TALP_STATE_NOT_USEFUL_GPU);
114 }
115 }
116
117
118 // Called from GPU backend plugin: CPU exits GPU runtime
119 void talp_gpu_exit_runtime(void) {
120
121 /* Observer and unknown threads may call GPU offload functions, but TALP must ignore them */
122 if (unlikely(thread_is_observer || !thread_is_known)) return;
123
124 spd_enter_dlb(thread_spd);
125 talp_info_t *talp_info = thread_spd->talp_info;
126 if (talp_info) {
127 /* Update sample */
128 talp_sample_update(talp_info);
129
130 /* Add statistic */
131 talp_sample_t *sample = talp_sample_get(talp_info);
132 DLB_ATOMIC_ADD_RLX(&sample->stats.num_gpu_runtime_calls, 1);
133
134 /* Out of Sync call -> useful */
135 talp_sample_set_state(talp_info, TALP_STATE_USEFUL);
136
137 /* Only when needed, update all regions */
138 if (talp_info->flags.external_profiler
139 && talp_sample_is_main()) {
140 talp_aggregate_samples_to_regions(talp_info);
141 }
142 }
143 }
144
145
146 // Called from GPU backend plugin: flush GPU data
147 void talp_gpu_submit(const gpu_measurements_t *measurements) {
148
149 gpu_sample.useful_time += measurements->useful_time;
150 gpu_sample.communication_time += measurements->communication_time;
151 gpu_sample.inactive_time += measurements->inactive_time;
152 }
153
154 // called from core
155 void talp_gpu_collect(gpu_measurements_t *out) {
156
157 fatal_cond(thread_is_observer, "Observer thread collecting GPU metrics. Please report bug.");
158 fatal_cond(!thread_is_known, "Unknown thread collecting GPU metrics. Please report bug.");
159
160 // flush GPU, may cause callback to talp_gpu_submit
161 gpu_backend_api->flush();
162
163 *out = gpu_sample;
164 gpu_sample = (const gpu_measurements_t){0};
165 }
166