-
-
Notifications
You must be signed in to change notification settings - Fork 332
/
offload.cpp
122 lines (95 loc) · 2.47 KB
/
offload.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#include "offload.h"
#include "profiling.h"
#include <pthread.h>
#include <inttypes.h>
#include <string.h>
#include <stdio.h>
static constexpr uint32_t QUEUE_SIZE = 8;
static pthread_t s_thread_handle;
static pthread_cond_t s_cond_work, s_cond_available;
static pthread_mutex_t s_queue_lock;
struct Work
{
std::function<void()> handler;
};
static Work s_queue[QUEUE_SIZE];
static uint32_t s_queue_head, s_queue_tail;
static bool s_quit;
static void *worker_thread(void *)
{
while (true)
{
Work *current_work = nullptr;
// Wait for work
pthread_mutex_lock(&s_queue_lock);
if (s_queue_head == s_queue_tail)
{
// queue empty and quit flag set, exit
if (s_quit)
{
pthread_mutex_unlock(&s_queue_lock);
break;
}
// wait for work signal
pthread_cond_wait(&s_cond_work, &s_queue_lock);
// quit flag was set and queue still empty, quit
if (s_quit && (s_queue_head == s_queue_tail))
{
pthread_mutex_unlock(&s_queue_lock);
break;
}
}
// get work
current_work = &s_queue[s_queue_tail % QUEUE_SIZE];
pthread_mutex_unlock(&s_queue_lock);
// execute
current_work->handler();
current_work->handler = nullptr;
// lock and move tail forward
pthread_mutex_lock(&s_queue_lock);
s_queue_tail++;
pthread_cond_signal(&s_cond_available);
pthread_mutex_unlock(&s_queue_lock);
}
return (void *)0;
}
void offload_start()
{
pthread_cond_init(&s_cond_available, nullptr);
pthread_cond_init(&s_cond_work, nullptr);
pthread_mutex_init(&s_queue_lock, nullptr);
s_queue_head = s_queue_tail = 0;
s_quit = false;
pthread_attr_t attr;
pthread_attr_init(&attr);
// Set affinity to core #0 since main runs on core #1
cpu_set_t set;
CPU_ZERO(&set);
CPU_SET(0, &set);
pthread_attr_setaffinity_np(&attr, sizeof(set), &set);
pthread_create(&s_thread_handle, &attr, worker_thread, nullptr);
}
void offload_stop()
{
pthread_mutex_lock(&s_queue_lock);
s_quit = true;
pthread_cond_signal(&s_cond_work);
pthread_mutex_unlock(&s_queue_lock);
printf("Waiting for offloaded work to finish...");
pthread_join(s_thread_handle, nullptr);
printf("Done\n");
}
void offload_add_work(std::function<void()> handler)
{
PROFILE_FUNCTION();
pthread_mutex_lock(&s_queue_lock);
if ((s_queue_head - s_queue_tail) == QUEUE_SIZE)
{
pthread_cond_wait(&s_cond_available, &s_queue_lock);
}
Work *work = &s_queue[s_queue_head % QUEUE_SIZE];
work->handler = handler;
s_queue_head++;
pthread_cond_signal(&s_cond_work);
pthread_mutex_unlock(&s_queue_lock);
}