Skip to content

Commit 2bf4055

Browse files
authored
Merge pull request #90 from intel/update-branch
Initial version of TCC tutorial which shows basic real-time tuning te… (#261)
2 parents efff667 + 4f1cc6a commit 2bf4055

File tree

13 files changed

+1738
-0
lines changed

13 files changed

+1738
-0
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
####################################################################################
2+
# Copyright (C) <2024> Intel Corporation
3+
#
4+
# Redistribution and use in source and binary forms, with or without modification,
5+
# are permitted provided that the following conditions are met:
6+
#
7+
# 1. Redistributions of source code must retain the above copyright notice,
8+
# this list of conditions and the following disclaimer.
9+
# 2. Redistributions in binary form must reproduce the above copyright notice,
10+
# this list of conditions and the following disclaimer in the documentation
11+
# and/or other materials provided with the distribution.
12+
# 3. Neither the name of the copyright holder nor the names of its contributors
13+
# may be used to endorse or promote products derived from this software
14+
# without specific prior written permission.
15+
#
16+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
18+
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
20+
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
21+
# OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
22+
# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23+
# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24+
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25+
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
26+
# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27+
#
28+
#
29+
# SPDX-License-Identifier: BSD-3-Clause
30+
####################################################################################
31+
CC=gcc
32+
CFLAGS=-Wall -Wextra -O2 -I/usr/local/include
33+
LDFLAGS=-L/usr/local/lib -lpaho-mqtt3c -lcjson
34+
TARGET=rt_linux_tutorial
35+
OBJ=rt_linux_tutorial.o pointer_chasing.o
36+
37+
.PHONY: all clean
38+
39+
all: $(TARGET)
40+
41+
$(TARGET): $(OBJ)
42+
$(CC) $(CFLAGS) -o $(TARGET) $(OBJ) $(LDFLAGS)
43+
44+
main.o: rt_linux_tutorial.c pointer_chasing.h
45+
$(CC) $(CFLAGS) -c rt_linux_tutorial.c
46+
47+
pointer_chasing.o: pointer_chasing.c pointer_chasing.h
48+
$(CC) $(CFLAGS) -c pointer_chasing.c
49+
50+
clean:
51+
rm -f $(TARGET) $(OBJ)

usecases/real-time/tcc_tutorial/README.md

Lines changed: 321 additions & 0 deletions
Large diffs are not rendered by default.
353 KB
Loading
40.7 KB
Loading
52 KB
Loading
52.8 KB
Loading
52.5 KB
Loading
50.2 KB
Loading
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
/*******************************************************************************
2+
Copyright (C) <2024> Intel Corporation
3+
4+
Redistribution and use in source and binary forms, with or without modification,
5+
are permitted provided that the following conditions are met:
6+
7+
1. Redistributions of source code must retain the above copyright notice,
8+
this list of conditions and the following disclaimer.
9+
2. Redistributions in binary form must reproduce the above copyright notice,
10+
this list of conditions and the following disclaimer in the documentation
11+
and/or other materials provided with the distribution.
12+
3. Neither the name of the copyright holder nor the names of its contributors
13+
may be used to endorse or promote products derived from this software
14+
without specific prior written permission.
15+
16+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
18+
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19+
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
20+
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
21+
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
22+
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23+
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24+
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25+
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
26+
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27+
28+
29+
SPDX-License-Identifier: BSD-3-Clause
30+
*******************************************************************************/
31+
#include "pointer_chasing.h"
32+
#include <math.h>
33+
#include <stdint.h>
34+
#include <stdio.h>
35+
#include <stdlib.h>
36+
#include <errno.h>
37+
38+
#define CACHE_LINE_SIZE 64 // Size of a cache line in bytes
39+
#define MINIMAL_NODE_NUMBER 6 // Required for pointer_chase_run_read_write_workload
40+
41+
/**
42+
* @brief Pointer-chase list node. The size of a node is equal to the size of one cache line.
43+
*
44+
*/
45+
struct cache_line_node_t
46+
{
47+
union
48+
{
49+
uint8_t buf[CACHE_LINE_SIZE];
50+
struct
51+
{
52+
cache_line_node_t* next;
53+
cache_line_node_t* prev;
54+
};
55+
};
56+
};
57+
58+
static cache_line_node_t* pointer_chasing_init_linear(cache_line_node_t* nodes, size_t n_nodes)
59+
{
60+
for (size_t i = 0; i < n_nodes; i++) {
61+
size_t next_id = (n_nodes + i + 1) % n_nodes;
62+
size_t prev_id = (n_nodes + i - 1) % n_nodes;
63+
nodes[i].prev = &(nodes[prev_id]);
64+
nodes[i].next = &(nodes[next_id]);
65+
}
66+
return nodes;
67+
}
68+
69+
static inline void pointer_chasing_swap_lines_far(cache_line_node_t* node1, cache_line_node_t* node2)
70+
{
71+
cache_line_node_t* node1_prev = node1->prev;
72+
cache_line_node_t* node1_next = node1->next;
73+
cache_line_node_t* node2_prev = node2->prev;
74+
cache_line_node_t* node2_next = node2->next;
75+
node1->prev->next = node2;
76+
node1->next->prev = node2;
77+
node2->next->prev = node1;
78+
node2->prev->next = node1;
79+
node1->prev = node2_prev;
80+
node1->next = node2_next;
81+
node2->next = node1_next;
82+
node2->prev = node1_prev;
83+
}
84+
static inline void pointer_chasing_swap_lines_near(cache_line_node_t* node1, cache_line_node_t* node2)
85+
{
86+
cache_line_node_t* node1_prev = node1->prev;
87+
cache_line_node_t* node2_next = node2->next;
88+
node1->prev->next = node2;
89+
node2->next->prev = node1;
90+
node1->prev = node2;
91+
node1->next = node2_next;
92+
node2->next = node1;
93+
node2->prev = node1_prev;
94+
}
95+
96+
static void pointer_chasing_swap_lines(cache_line_node_t* node1, cache_line_node_t* node2)
97+
{
98+
if (node1->prev == node2) {
99+
pointer_chasing_swap_lines_near(node2, node1);
100+
} else if (node1->next == node2) {
101+
pointer_chasing_swap_lines_near(node1, node2);
102+
} else if (node1 != node2) {
103+
pointer_chasing_swap_lines_far(node1, node2);
104+
}
105+
}
106+
107+
static inline cache_line_node_t* pointer_chase_run_read_workload_internal(cache_line_node_t* nodes, size_t n_nodes)
108+
{
109+
while (n_nodes--) {
110+
nodes = nodes->next;
111+
}
112+
return nodes;
113+
}
114+
115+
cache_line_node_t* pointer_chase_randomise(cache_line_node_t* nodes,
116+
size_t n_nodes,
117+
pointer_chase_random_generator_t generator)
118+
{
119+
for (size_t i = 0; i < n_nodes; i++) {
120+
size_t rand = generator() % n_nodes;
121+
pointer_chasing_swap_lines(&nodes[i], &nodes[rand]);
122+
}
123+
return nodes;
124+
}
125+
cache_line_node_t* pointer_chase_create_linear(void* buffer, size_t size)
126+
{
127+
size_t n_nodes = size / sizeof(cache_line_node_t);
128+
printf("Pointer Chasing: Buffer Size %ld\n", size);
129+
printf("Pointer Chasing: Number of Nodes %ld\n", n_nodes);
130+
if (buffer == NULL || n_nodes < MINIMAL_NODE_NUMBER) {
131+
errno = EINVAL;
132+
return NULL;
133+
}
134+
return pointer_chasing_init_linear((cache_line_node_t*)buffer, n_nodes);
135+
}
136+
137+
cache_line_node_t* pointer_chase_create_random(void* buffer, size_t size, pointer_chase_random_generator_t generator)
138+
{
139+
if (generator == NULL) {
140+
errno = EINVAL;
141+
return NULL;
142+
}
143+
cache_line_node_t* self = pointer_chase_create_linear((cache_line_node_t*)buffer, size);
144+
if (self == NULL) {
145+
return NULL;
146+
}
147+
return pointer_chase_randomise(self, size / sizeof(cache_line_node_t), generator);
148+
}
149+
150+
__attribute__((optimize("-O0"))) cache_line_node_t* pointer_chase_run_read_workload(cache_line_node_t* nodes,
151+
size_t n_nodes)
152+
{
153+
return pointer_chase_run_read_workload_internal(nodes, n_nodes);
154+
}
155+
156+
__attribute__((optimize("-O0"))) cache_line_node_t* pointer_chase_run_workload_read_cyclic(cache_line_node_t* nodes,
157+
size_t n_cycles)
158+
{
159+
register cache_line_node_t* start = nodes;
160+
for (size_t cycle = 0; cycle < n_cycles; cycle++) {
161+
while (nodes != start) {
162+
nodes = nodes->next;
163+
}
164+
}
165+
return nodes;
166+
}
167+
168+
cache_line_node_t* pointer_chase_run_read_write_workload(cache_line_node_t* nodes, size_t n_nodes)
169+
{
170+
while (n_nodes--) {
171+
cache_line_node_t* node1 = nodes;
172+
cache_line_node_t* node2 = pointer_chase_run_read_workload_internal(node1, 3);
173+
nodes = pointer_chase_run_read_workload_internal(node2, 3);
174+
pointer_chasing_swap_lines_far(node1, node2);
175+
}
176+
return nodes;
177+
}
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
/*******************************************************************************
2+
Copyright (C) <2024> Intel Corporation
3+
4+
Redistribution and use in source and binary forms, with or without modification,
5+
are permitted provided that the following conditions are met:
6+
7+
1. Redistributions of source code must retain the above copyright notice,
8+
this list of conditions and the following disclaimer.
9+
2. Redistributions in binary form must reproduce the above copyright notice,
10+
this list of conditions and the following disclaimer in the documentation
11+
and/or other materials provided with the distribution.
12+
3. Neither the name of the copyright holder nor the names of its contributors
13+
may be used to endorse or promote products derived from this software
14+
without specific prior written permission.
15+
16+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
18+
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19+
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
20+
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
21+
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
22+
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23+
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24+
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25+
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
26+
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27+
28+
29+
SPDX-License-Identifier: BSD-3-Clause
30+
*******************************************************************************/
31+
32+
/**
33+
* The pointer-chase workload represents a simple linked list. Each node in this
34+
* list contains pointers to the previous element and the next element of the list.
35+
* The size of a node is equal to the size of a cache line (64 bytes).
36+
*
37+
* The pointer-chase workload has two modes of initialization:
38+
* linear and random. In the linear mode, for each node in the list, the pointer to the
39+
* previous element points to the previous element in memory. The pointer to the next
40+
* element points to the next element in memory.
41+
* In the random mode, for each node of the list, the pointer to the previous element
42+
* and the pointer to the next element point to random elements in memory.
43+
*
44+
* In the linear mode, the hardware prefetchers can “read-ahead”
45+
* and prime the cache with the data.
46+
* In the random mode, there is no spatial locality,
47+
* and the data is generally not prefetched into cache. As a result, each access
48+
* of an element of the buffer incurs the latency for whatever level of the memory
49+
* hierarchy that the library “locked” the buffer into.
50+
*
51+
*/
52+
53+
#ifndef _TCC_POINTER_CHASING_H_
54+
#define _TCC_POINTER_CHASING_H_
55+
56+
#include <stddef.h>
57+
58+
#ifdef __cplusplus
59+
extern "C" {
60+
#endif
61+
62+
typedef struct cache_line_node_t cache_line_node_t;
63+
typedef struct cache_line_it_t cache_line_it_t;
64+
typedef long int (*pointer_chase_random_generator_t)(void);
65+
66+
67+
/**
68+
* \brief Creates a linear pointer-chase node list.
69+
* Creates a cyclical linked list from the input buffer of elements continuously placed in memory.
70+
* The last element refers to the first element of the list. The size of each node is equal to the size of a cache line.
71+
* \param buffer [in] pointer to the memory buffer where the pointer-chase list will be located
72+
* \param size [in] size of the memory buffer in bytes
73+
* \return pointer to the first node of the linked list
74+
**/
75+
cache_line_node_t* pointer_chase_create_linear(void* buffer, size_t size);
76+
77+
78+
/**
79+
* \brief Creates a random pointer-chase node list.
80+
* Creates a cyclical linked list from the input buffer with elements that randomly connect with each other.
81+
* The last element refers to the first element. The size of each node is equal to the size of a cache line.
82+
* \param buffer [in] pointer to the memory buffer where the pointer-chase list will be located
83+
* \param size [in] size of the memory buffer in bytes
84+
* \return pointer to the first node of the linked list
85+
**/
86+
cache_line_node_t* pointer_chase_create_random(void* buffer, size_t size, pointer_chase_random_generator_t generator);
87+
88+
/**
89+
* \brief Executes the pointer-chase read workload for a given number of nodes.
90+
* The workload accesses the next item of the linked list and generates one cache line read.
91+
*
92+
* Warning: This function does not validate input parameters to improve performance.
93+
* \param nodes [in] pointer to the initial pointer-chase node
94+
* \param n_nodes [in] number of nodes to iterate
95+
* \return the next node of the linked list
96+
**/
97+
cache_line_node_t* pointer_chase_run_read_workload(cache_line_node_t* nodes, size_t n_nodes);
98+
99+
100+
/**
101+
* \brief Executes the pointer-chase read workload for all nodes in a list.
102+
* The workload accesses the next item of the linked list and generates one cache line read. This function
103+
* iterates the linked list until the last element of the list.
104+
*
105+
* Warning: This function does not validate input parameters to increase performance.
106+
* \param nodes [in] pointer to the initial pointer-chase node
107+
* \param n_cycles [in] number of times the workload should iterate over the all nodes of the list
108+
* \return the next node of the linked list
109+
**/
110+
cache_line_node_t* pointer_chase_run_workload_read_cyclic(cache_line_node_t* nodes, size_t n_cycles);
111+
112+
/**
113+
* \brief Executes the pointer-chase read-write workload for a given number of nodes multiplied by six.
114+
* On each iteration, the workload reads 3 + 3 nodes and swaps it.
115+
*
116+
* Warning: This function does not validate input parameters to improve performance.
117+
* \param nodes [in] pointer to the initial pointer-chase node
118+
* \param n_nodes [in] number of nodes to iterate
119+
* \return the next node of the linked list
120+
**/
121+
cache_line_node_t* pointer_chase_run_read_write_workload(cache_line_node_t* nodes, size_t n_nodes);
122+
123+
#ifdef __cplusplus
124+
}
125+
#endif
126+
127+
#endif // _TCC_POINTER_CHASING_H_

0 commit comments

Comments
 (0)