Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
@@ -0,0 +1,2 @@
# SPDX-License-Identifier: GPL-2.0-only
sync_test
@@ -0,0 +1,38 @@
# SPDX-License-Identifier: GPL-2.0
CFLAGS += -O2 -g -std=gnu89 -pthread -Wall -Wextra
CFLAGS += $(KHDR_INCLUDES)
LDFLAGS += -pthread
.PHONY: all clean
include ../lib.mk
# lib.mk TEST_CUSTOM_PROGS var is for custom tests that need special
# build rules. lib.mk will run and install them.
TEST_CUSTOM_PROGS := $(OUTPUT)/sync_test
all: $(TEST_CUSTOM_PROGS)
OBJS = sync_test.o sync.o
TESTS += sync_alloc.o
TESTS += sync_fence.o
TESTS += sync_merge.o
TESTS += sync_wait.o
TESTS += sync_stress_parallelism.o
TESTS += sync_stress_consumer.o
TESTS += sync_stress_merge.o
OBJS := $(patsubst %,$(OUTPUT)/%,$(OBJS))
TESTS := $(patsubst %,$(OUTPUT)/%,$(TESTS))
$(TEST_CUSTOM_PROGS): $(TESTS) $(OBJS)
$(CC) -o $(TEST_CUSTOM_PROGS) $(OBJS) $(TESTS) $(CFLAGS) $(LDFLAGS)
$(OBJS): $(OUTPUT)/%.o: %.c
$(CC) -c $^ -o $@ $(CFLAGS)
$(TESTS): $(OUTPUT)/%.o: %.c
$(CC) -c $^ -o $@
EXTRA_CLEAN := $(TEST_CUSTOM_PROGS) $(OBJS) $(TESTS)
@@ -0,0 +1,2 @@
CONFIG_STAGING=y
CONFIG_SW_SYNC=y
@@ -0,0 +1,46 @@
/*
* sw_sync abstraction
*
* Copyright 2015-2016 Collabora Ltd.
*
* Based on the implementation from the Android Open Source Project,
*
* Copyright 2013 Google, Inc
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef SELFTESTS_SW_SYNC_H
#define SELFTESTS_SW_SYNC_H
/*
* sw_sync is mainly intended for testing and should not be compiled into
* production kernels
*/
int sw_sync_timeline_create(void);
int sw_sync_timeline_is_valid(int fd);
int sw_sync_timeline_inc(int fd, unsigned int count);
void sw_sync_timeline_destroy(int fd);
int sw_sync_fence_create(int fd, const char *name, unsigned int value);
int sw_sync_fence_is_valid(int fd);
void sw_sync_fence_destroy(int fd);
#endif
@@ -0,0 +1,221 @@
/*
* sync / sw_sync abstraction
* Copyright 2015-2016 Collabora Ltd.
*
* Based on the implementation from the Android Open Source Project,
*
* Copyright 2012 Google, Inc
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include <fcntl.h>
#include <malloc.h>
#include <poll.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "sync.h"
#include "sw_sync.h"
#include <linux/sync_file.h>
/* SW_SYNC ioctls */
struct sw_sync_create_fence_data {
__u32 value;
char name[32];
__s32 fence;
};
#define SW_SYNC_IOC_MAGIC 'W'
#define SW_SYNC_IOC_CREATE_FENCE _IOWR(SW_SYNC_IOC_MAGIC, 0,\
struct sw_sync_create_fence_data)
#define SW_SYNC_IOC_INC _IOW(SW_SYNC_IOC_MAGIC, 1, __u32)
int sync_wait(int fd, int timeout)
{
struct pollfd fds;
fds.fd = fd;
fds.events = POLLIN | POLLERR;
return poll(&fds, 1, timeout);
}
int sync_merge(const char *name, int fd1, int fd2)
{
struct sync_merge_data data = {};
int err;
data.fd2 = fd2;
strncpy(data.name, name, sizeof(data.name) - 1);
data.name[sizeof(data.name) - 1] = '\0';
err = ioctl(fd1, SYNC_IOC_MERGE, &data);
if (err < 0)
return err;
return data.fence;
}
static struct sync_file_info *sync_file_info(int fd)
{
struct sync_file_info *info;
struct sync_fence_info *fence_info;
int err, num_fences;
info = calloc(1, sizeof(*info));
if (info == NULL)
return NULL;
err = ioctl(fd, SYNC_IOC_FILE_INFO, info);
if (err < 0) {
free(info);
return NULL;
}
num_fences = info->num_fences;
if (num_fences) {
info->flags = 0;
info->num_fences = num_fences;
fence_info = calloc(num_fences, sizeof(*fence_info));
if (!fence_info) {
free(info);
return NULL;
}
info->sync_fence_info = (uint64_t)(unsigned long)fence_info;
err = ioctl(fd, SYNC_IOC_FILE_INFO, info);
if (err < 0) {
free(fence_info);
free(info);
return NULL;
}
}
return info;
}
static void sync_file_info_free(struct sync_file_info *info)
{
free((void *)(unsigned long)info->sync_fence_info);
free(info);
}
int sync_fence_size(int fd)
{
int count;
struct sync_file_info *info = sync_file_info(fd);
if (!info)
return 0;
count = info->num_fences;
sync_file_info_free(info);
return count;
}
int sync_fence_count_with_status(int fd, int status)
{
unsigned int i, count = 0;
struct sync_fence_info *fence_info = NULL;
struct sync_file_info *info = sync_file_info(fd);
if (!info)
return -1;
fence_info = (struct sync_fence_info *)(unsigned long)info->sync_fence_info;
for (i = 0 ; i < info->num_fences ; i++) {
if (fence_info[i].status == status)
count++;
}
sync_file_info_free(info);
return count;
}
int sw_sync_timeline_create(void)
{
return open("/sys/kernel/debug/sync/sw_sync", O_RDWR);
}
int sw_sync_timeline_inc(int fd, unsigned int count)
{
__u32 arg = count;
return ioctl(fd, SW_SYNC_IOC_INC, &arg);
}
int sw_sync_timeline_is_valid(int fd)
{
int status;
if (fd == -1)
return 0;
status = fcntl(fd, F_GETFD, 0);
return (status >= 0);
}
void sw_sync_timeline_destroy(int fd)
{
if (sw_sync_timeline_is_valid(fd))
close(fd);
}
int sw_sync_fence_create(int fd, const char *name, unsigned int value)
{
struct sw_sync_create_fence_data data = {};
int err;
data.value = value;
strncpy(data.name, name, sizeof(data.name) - 1);
data.name[sizeof(data.name) - 1] = '\0';
err = ioctl(fd, SW_SYNC_IOC_CREATE_FENCE, &data);
if (err < 0)
return err;
return data.fence;
}
int sw_sync_fence_is_valid(int fd)
{
/* Same code! */
return sw_sync_timeline_is_valid(fd);
}
void sw_sync_fence_destroy(int fd)
{
if (sw_sync_fence_is_valid(fd))
close(fd);
}
@@ -0,0 +1,40 @@
/*
* sync abstraction
* Copyright 2015-2016 Collabora Ltd.
*
* Based on the implementation from the Android Open Source Project,
*
* Copyright 2012 Google, Inc
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef SELFTESTS_SYNC_H
#define SELFTESTS_SYNC_H
#define FENCE_STATUS_ERROR (-1)
#define FENCE_STATUS_ACTIVE (0)
#define FENCE_STATUS_SIGNALED (1)
int sync_wait(int fd, int timeout);
int sync_merge(const char *name, int fd1, int fd2);
int sync_fence_size(int fd);
int sync_fence_count_with_status(int fd, int status);
#endif
@@ -0,0 +1,74 @@
/*
* sync allocation tests
* Copyright 2015-2016 Collabora Ltd.
*
* Based on the implementation from the Android Open Source Project,
*
* Copyright 2012 Google, Inc
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include "sync.h"
#include "sw_sync.h"
#include "synctest.h"
int test_alloc_timeline(void)
{
int timeline, valid;
timeline = sw_sync_timeline_create();
valid = sw_sync_timeline_is_valid(timeline);
ASSERT(valid, "Failure allocating timeline\n");
sw_sync_timeline_destroy(timeline);
return 0;
}
int test_alloc_fence(void)
{
int timeline, fence, valid;
timeline = sw_sync_timeline_create();
valid = sw_sync_timeline_is_valid(timeline);
ASSERT(valid, "Failure allocating timeline\n");
fence = sw_sync_fence_create(timeline, "allocFence", 1);
valid = sw_sync_fence_is_valid(fence);
ASSERT(valid, "Failure allocating fence\n");
sw_sync_fence_destroy(fence);
sw_sync_timeline_destroy(timeline);
return 0;
}
int test_alloc_fence_negative(void)
{
int fence, timeline;
timeline = sw_sync_timeline_create();
ASSERT(timeline > 0, "Failure allocating timeline\n");
fence = sw_sync_fence_create(-1, "fence", 1);
ASSERT(fence < 0, "Success allocating negative fence\n");
sw_sync_fence_destroy(fence);
sw_sync_timeline_destroy(timeline);
return 0;
}
@@ -0,0 +1,132 @@
/*
* sync fence tests with one timeline
* Copyright 2015-2016 Collabora Ltd.
*
* Based on the implementation from the Android Open Source Project,
*
* Copyright 2012 Google, Inc
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include "sync.h"
#include "sw_sync.h"
#include "synctest.h"
int test_fence_one_timeline_wait(void)
{
int fence, valid, ret;
int timeline = sw_sync_timeline_create();
valid = sw_sync_timeline_is_valid(timeline);
ASSERT(valid, "Failure allocating timeline\n");
fence = sw_sync_fence_create(timeline, "allocFence", 5);
valid = sw_sync_fence_is_valid(fence);
ASSERT(valid, "Failure allocating fence\n");
/* Wait on fence until timeout */
ret = sync_wait(fence, 0);
ASSERT(ret == 0, "Failure waiting on fence until timeout\n");
/* Advance timeline from 0 -> 1 */
ret = sw_sync_timeline_inc(timeline, 1);
ASSERT(ret == 0, "Failure advancing timeline\n");
/* Wait on fence until timeout */
ret = sync_wait(fence, 0);
ASSERT(ret == 0, "Failure waiting on fence until timeout\n");
/* Signal the fence */
ret = sw_sync_timeline_inc(timeline, 4);
ASSERT(ret == 0, "Failure signaling the fence\n");
/* Wait successfully */
ret = sync_wait(fence, 0);
ASSERT(ret > 0, "Failure waiting on fence\n");
/* Go even further, and confirm wait still succeeds */
ret = sw_sync_timeline_inc(timeline, 10);
ASSERT(ret == 0, "Failure going further\n");
ret = sync_wait(fence, 0);
ASSERT(ret > 0, "Failure waiting ahead\n");
sw_sync_fence_destroy(fence);
sw_sync_timeline_destroy(timeline);
return 0;
}
int test_fence_one_timeline_merge(void)
{
int a, b, c, d, valid;
int timeline = sw_sync_timeline_create();
/* create fence a,b,c and then merge them all into fence d */
a = sw_sync_fence_create(timeline, "allocFence", 1);
b = sw_sync_fence_create(timeline, "allocFence", 2);
c = sw_sync_fence_create(timeline, "allocFence", 3);
valid = sw_sync_fence_is_valid(a) &&
sw_sync_fence_is_valid(b) &&
sw_sync_fence_is_valid(c);
ASSERT(valid, "Failure allocating fences\n");
d = sync_merge("mergeFence", b, a);
d = sync_merge("mergeFence", c, d);
valid = sw_sync_fence_is_valid(d);
ASSERT(valid, "Failure merging fences\n");
/* confirm all fences have one active point (even d) */
ASSERT(sync_fence_count_with_status(a, FENCE_STATUS_ACTIVE) == 1,
"a has too many active fences!\n");
ASSERT(sync_fence_count_with_status(a, FENCE_STATUS_ACTIVE) == 1,
"b has too many active fences!\n");
ASSERT(sync_fence_count_with_status(a, FENCE_STATUS_ACTIVE) == 1,
"c has too many active fences!\n");
ASSERT(sync_fence_count_with_status(a, FENCE_STATUS_ACTIVE) == 1,
"d has too many active fences!\n");
/* confirm that d is not signaled until the max of a,b,c */
sw_sync_timeline_inc(timeline, 1);
ASSERT(sync_fence_count_with_status(a, FENCE_STATUS_SIGNALED) == 1,
"a did not signal!\n");
ASSERT(sync_fence_count_with_status(d, FENCE_STATUS_ACTIVE) == 1,
"d signaled too early!\n");
sw_sync_timeline_inc(timeline, 1);
ASSERT(sync_fence_count_with_status(b, FENCE_STATUS_SIGNALED) == 1,
"b did not signal!\n");
ASSERT(sync_fence_count_with_status(d, FENCE_STATUS_ACTIVE) == 1,
"d signaled too early!\n");
sw_sync_timeline_inc(timeline, 1);
ASSERT(sync_fence_count_with_status(c, FENCE_STATUS_SIGNALED) == 1,
"c did not signal!\n");
ASSERT(sync_fence_count_with_status(d, FENCE_STATUS_ACTIVE) == 0 &&
sync_fence_count_with_status(d, FENCE_STATUS_SIGNALED) == 1,
"d did not signal!\n");
sw_sync_fence_destroy(d);
sw_sync_fence_destroy(c);
sw_sync_fence_destroy(b);
sw_sync_fence_destroy(a);
sw_sync_timeline_destroy(timeline);
return 0;
}
@@ -0,0 +1,60 @@
/*
* sync fence merge tests
* Copyright 2015-2016 Collabora Ltd.
*
* Based on the implementation from the Android Open Source Project,
*
* Copyright 2012 Google, Inc
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include "sync.h"
#include "sw_sync.h"
#include "synctest.h"
int test_fence_merge_same_fence(void)
{
int fence, valid, merged;
int timeline = sw_sync_timeline_create();
valid = sw_sync_timeline_is_valid(timeline);
ASSERT(valid, "Failure allocating timeline\n");
fence = sw_sync_fence_create(timeline, "allocFence", 5);
valid = sw_sync_fence_is_valid(fence);
ASSERT(valid, "Failure allocating fence\n");
merged = sync_merge("mergeFence", fence, fence);
valid = sw_sync_fence_is_valid(fence);
ASSERT(valid, "Failure merging fence\n");
ASSERT(sync_fence_count_with_status(merged, FENCE_STATUS_SIGNALED) == 0,
"fence signaled too early!\n");
sw_sync_timeline_inc(timeline, 5);
ASSERT(sync_fence_count_with_status(merged, FENCE_STATUS_SIGNALED) == 1,
"fence did not signal!\n");
sw_sync_fence_destroy(merged);
sw_sync_fence_destroy(fence);
sw_sync_timeline_destroy(timeline);
return 0;
}
@@ -0,0 +1,185 @@
/*
* sync stress test: producer/consumer
* Copyright 2015-2016 Collabora Ltd.
*
* Based on the implementation from the Android Open Source Project,
*
* Copyright 2012 Google, Inc
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include <pthread.h>
#include "sync.h"
#include "sw_sync.h"
#include "synctest.h"
/* IMPORTANT NOTE: if you see this test failing on your system, it may be
* due to a shortage of file descriptors. Please ensure your system has
* a sensible limit for this test to finish correctly.
*/
/* Returns 1 on error, 0 on success */
static int busy_wait_on_fence(int fence)
{
int error, active;
do {
error = sync_fence_count_with_status(fence, FENCE_STATUS_ERROR);
ASSERT(error == 0, "Error occurred on fence\n");
active = sync_fence_count_with_status(fence,
FENCE_STATUS_ACTIVE);
} while (active);
return 0;
}
static struct {
int iterations;
int threads;
int counter;
int consumer_timeline;
int *producer_timelines;
pthread_mutex_t lock;
} test_data_mpsc;
static int mpsc_producer_thread(void *d)
{
int id = (long)d;
int fence, valid, i;
int *producer_timelines = test_data_mpsc.producer_timelines;
int consumer_timeline = test_data_mpsc.consumer_timeline;
int iterations = test_data_mpsc.iterations;
for (i = 0; i < iterations; i++) {
fence = sw_sync_fence_create(consumer_timeline, "fence", i);
valid = sw_sync_fence_is_valid(fence);
ASSERT(valid, "Failure creating fence\n");
/*
* Wait for the consumer to finish. Use alternate
* means of waiting on the fence
*/
if ((iterations + id) % 8 != 0) {
ASSERT(sync_wait(fence, -1) > 0,
"Failure waiting on fence\n");
} else {
ASSERT(busy_wait_on_fence(fence) == 0,
"Failure waiting on fence\n");
}
/*
* Every producer increments the counter, the consumer
* checks and erases it
*/
pthread_mutex_lock(&test_data_mpsc.lock);
test_data_mpsc.counter++;
pthread_mutex_unlock(&test_data_mpsc.lock);
ASSERT(sw_sync_timeline_inc(producer_timelines[id], 1) == 0,
"Error advancing producer timeline\n");
sw_sync_fence_destroy(fence);
}
return 0;
}
static int mpcs_consumer_thread(void)
{
int fence, merged, tmp, valid, it, i;
int *producer_timelines = test_data_mpsc.producer_timelines;
int consumer_timeline = test_data_mpsc.consumer_timeline;
int iterations = test_data_mpsc.iterations;
int n = test_data_mpsc.threads;
for (it = 1; it <= iterations; it++) {
fence = sw_sync_fence_create(producer_timelines[0], "name", it);
for (i = 1; i < n; i++) {
tmp = sw_sync_fence_create(producer_timelines[i],
"name", it);
merged = sync_merge("name", tmp, fence);
sw_sync_fence_destroy(tmp);
sw_sync_fence_destroy(fence);
fence = merged;
}
valid = sw_sync_fence_is_valid(fence);
ASSERT(valid, "Failure merging fences\n");
/*
* Make sure we see an increment from every producer thread.
* Vary the means by which we wait.
*/
if (iterations % 8 != 0) {
ASSERT(sync_wait(fence, -1) > 0,
"Producers did not increment as expected\n");
} else {
ASSERT(busy_wait_on_fence(fence) == 0,
"Producers did not increment as expected\n");
}
ASSERT(test_data_mpsc.counter == n * it,
"Counter value mismatch!\n");
/* Release the producer threads */
ASSERT(sw_sync_timeline_inc(consumer_timeline, 1) == 0,
"Failure releasing producer threads\n");
sw_sync_fence_destroy(fence);
}
return 0;
}
int test_consumer_stress_multi_producer_single_consumer(void)
{
int iterations = 1 << 12;
int n = 5;
long i, ret;
int producer_timelines[n];
int consumer_timeline;
pthread_t threads[n];
consumer_timeline = sw_sync_timeline_create();
for (i = 0; i < n; i++)
producer_timelines[i] = sw_sync_timeline_create();
test_data_mpsc.producer_timelines = producer_timelines;
test_data_mpsc.consumer_timeline = consumer_timeline;
test_data_mpsc.iterations = iterations;
test_data_mpsc.threads = n;
test_data_mpsc.counter = 0;
pthread_mutex_init(&test_data_mpsc.lock, NULL);
for (i = 0; i < n; i++) {
pthread_create(&threads[i], NULL, (void * (*)(void *))
mpsc_producer_thread, (void *)i);
}
/* Consumer thread runs here */
ret = mpcs_consumer_thread();
for (i = 0; i < n; i++)
pthread_join(threads[i], NULL);
return ret;
}
@@ -0,0 +1,115 @@
/*
* sync stress test: merging
* Copyright 2015-2016 Collabora Ltd.
*
* Based on the implementation from the Android Open Source Project,
*
* Copyright 2012 Google, Inc
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "sync.h"
#include "sw_sync.h"
#include "synctest.h"
int test_merge_stress_random_merge(void)
{
int i, size, ret;
int timeline_count = 32;
int merge_count = 1024 * 32;
int timelines[timeline_count];
int fence_map[timeline_count];
int fence, tmpfence, merged, valid;
int timeline, timeline_offset, sync_point;
srand(time(NULL));
for (i = 0; i < timeline_count; i++)
timelines[i] = sw_sync_timeline_create();
fence = sw_sync_fence_create(timelines[0], "fence", 0);
valid = sw_sync_fence_is_valid(fence);
ASSERT(valid, "Failure creating fence\n");
memset(fence_map, -1, sizeof(fence_map));
fence_map[0] = 0;
/*
* Randomly create sync_points out of a fixed set of timelines,
* and merge them together
*/
for (i = 0; i < merge_count; i++) {
/* Generate sync_point. */
timeline_offset = rand() % timeline_count;
timeline = timelines[timeline_offset];
sync_point = rand();
/* Keep track of the latest sync_point in each timeline. */
if (fence_map[timeline_offset] == -1)
fence_map[timeline_offset] = sync_point;
else if (fence_map[timeline_offset] < sync_point)
fence_map[timeline_offset] = sync_point;
/* Merge */
tmpfence = sw_sync_fence_create(timeline, "fence", sync_point);
merged = sync_merge("merge", tmpfence, fence);
sw_sync_fence_destroy(tmpfence);
sw_sync_fence_destroy(fence);
fence = merged;
valid = sw_sync_fence_is_valid(merged);
ASSERT(valid, "Failure creating fence i\n");
}
size = 0;
for (i = 0; i < timeline_count; i++)
if (fence_map[i] != -1)
size++;
/* Confirm our map matches the fence. */
ASSERT(sync_fence_size(fence) == size,
"Quantity of elements not matching\n");
/* Trigger the merged fence */
for (i = 0; i < timeline_count; i++) {
if (fence_map[i] != -1) {
ret = sync_wait(fence, 0);
ASSERT(ret == 0,
"Failure waiting on fence until timeout\n");
/* Increment the timeline to the last sync_point */
sw_sync_timeline_inc(timelines[i], fence_map[i]);
}
}
/* Check that the fence is triggered. */
ret = sync_wait(fence, 0);
ASSERT(ret > 0, "Failure triggering fence\n");
sw_sync_fence_destroy(fence);
for (i = 0; i < timeline_count; i++)
sw_sync_timeline_destroy(timelines[i]);
return 0;
}
@@ -0,0 +1,111 @@
/*
* sync stress test: parallelism
* Copyright 2015-2016 Collabora Ltd.
*
* Based on the implementation from the Android Open Source Project,
*
* Copyright 2012 Google, Inc
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include <pthread.h>
#include "sync.h"
#include "sw_sync.h"
#include "synctest.h"
static struct {
int iterations;
int timeline;
int counter;
} test_data_two_threads;
static int test_stress_two_threads_shared_timeline_thread(void *d)
{
int thread_id = (long)d;
int timeline = test_data_two_threads.timeline;
int iterations = test_data_two_threads.iterations;
int fence, valid, ret, i;
for (i = 0; i < iterations; i++) {
fence = sw_sync_fence_create(timeline, "fence",
i * 2 + thread_id);
valid = sw_sync_fence_is_valid(fence);
ASSERT(valid, "Failure allocating fence\n");
/* Wait on the prior thread to complete */
ret = sync_wait(fence, -1);
ASSERT(ret > 0, "Problem occurred on prior thread\n");
/*
* Confirm the previous thread's writes are visible
* and then increment
*/
ASSERT(test_data_two_threads.counter == i * 2 + thread_id,
"Counter got damaged!\n");
test_data_two_threads.counter++;
/* Kick off the other thread */
ret = sw_sync_timeline_inc(timeline, 1);
ASSERT(ret == 0, "Advancing timeline failed\n");
sw_sync_fence_destroy(fence);
}
return 0;
}
int test_stress_two_threads_shared_timeline(void)
{
pthread_t a, b;
int valid;
int timeline = sw_sync_timeline_create();
valid = sw_sync_timeline_is_valid(timeline);
ASSERT(valid, "Failure allocating timeline\n");
test_data_two_threads.iterations = 1 << 16;
test_data_two_threads.counter = 0;
test_data_two_threads.timeline = timeline;
/*
* Use a single timeline to synchronize two threads
* hammmering on the same counter.
*/
pthread_create(&a, NULL, (void *(*)(void *))
test_stress_two_threads_shared_timeline_thread,
(void *)0);
pthread_create(&b, NULL, (void *(*)(void *))
test_stress_two_threads_shared_timeline_thread,
(void *)1);
pthread_join(a, NULL);
pthread_join(b, NULL);
/* make sure the threads did not trample on one another */
ASSERT(test_data_two_threads.counter ==
test_data_two_threads.iterations * 2,
"Counter has unexpected value\n");
sw_sync_timeline_destroy(timeline);
return 0;
}
@@ -0,0 +1,113 @@
/*
* sync test runner
* Copyright 2015-2016 Collabora Ltd.
*
* Based on the implementation from the Android Open Source Project,
*
* Copyright 2012 Google, Inc
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <errno.h>
#include <string.h>
#include "kselftest.h"
#include "synctest.h"
static int run_test(int (*test)(void), char *name)
{
int result;
pid_t childpid;
int ret;
fflush(stdout);
childpid = fork();
if (childpid) {
waitpid(childpid, &result, 0);
if (WIFEXITED(result)) {
ret = WEXITSTATUS(result);
if (!ret)
ksft_test_result_pass("[RUN]\t%s\n", name);
else
ksft_test_result_fail("[RUN]\t%s\n", name);
return ret;
}
return 1;
}
exit(test());
}
static void sync_api_supported(void)
{
struct stat sbuf;
int ret;
ret = stat("/sys/kernel/debug/sync/sw_sync", &sbuf);
if (!ret)
return;
if (errno == ENOENT)
ksft_exit_skip("Sync framework not supported by kernel\n");
if (errno == EACCES)
ksft_exit_skip("Run Sync test as root.\n");
ksft_exit_fail_msg("stat failed on /sys/kernel/debug/sync/sw_sync: %s",
strerror(errno));
}
int main(void)
{
int err;
ksft_print_header();
sync_api_supported();
ksft_set_plan(3 + 7);
ksft_print_msg("[RUN]\tTesting sync framework\n");
RUN_TEST(test_alloc_timeline);
RUN_TEST(test_alloc_fence);
RUN_TEST(test_alloc_fence_negative);
RUN_TEST(test_fence_one_timeline_wait);
RUN_TEST(test_fence_one_timeline_merge);
RUN_TEST(test_fence_merge_same_fence);
RUN_TEST(test_fence_multi_timeline_wait);
RUN_TEST(test_stress_two_threads_shared_timeline);
RUN_TEST(test_consumer_stress_multi_producer_single_consumer);
RUN_TEST(test_merge_stress_random_merge);
err = ksft_get_fail_cnt();
if (err)
ksft_exit_fail_msg("%d out of %d sync tests failed\n",
err, ksft_test_num());
ksft_exit_pass();
}
@@ -0,0 +1,91 @@
/*
* sync fence wait tests
* Copyright 2015-2016 Collabora Ltd.
*
* Based on the implementation from the Android Open Source Project,
*
* Copyright 2012 Google, Inc
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include "sync.h"
#include "sw_sync.h"
#include "synctest.h"
int test_fence_multi_timeline_wait(void)
{
int timelineA, timelineB, timelineC;
int fenceA, fenceB, fenceC, merged;
int valid, active, signaled, ret;
timelineA = sw_sync_timeline_create();
timelineB = sw_sync_timeline_create();
timelineC = sw_sync_timeline_create();
fenceA = sw_sync_fence_create(timelineA, "fenceA", 5);
fenceB = sw_sync_fence_create(timelineB, "fenceB", 5);
fenceC = sw_sync_fence_create(timelineC, "fenceC", 5);
merged = sync_merge("mergeFence", fenceB, fenceA);
merged = sync_merge("mergeFence", fenceC, merged);
valid = sw_sync_fence_is_valid(merged);
ASSERT(valid, "Failure merging fence from various timelines\n");
/* Confirm fence isn't signaled */
active = sync_fence_count_with_status(merged, FENCE_STATUS_ACTIVE);
ASSERT(active == 3, "Fence signaled too early!\n");
ret = sync_wait(merged, 0);
ASSERT(ret == 0,
"Failure waiting on fence until timeout\n");
ret = sw_sync_timeline_inc(timelineA, 5);
active = sync_fence_count_with_status(merged, FENCE_STATUS_ACTIVE);
signaled = sync_fence_count_with_status(merged, FENCE_STATUS_SIGNALED);
ASSERT(active == 2 && signaled == 1,
"Fence did not signal properly!\n");
ret = sw_sync_timeline_inc(timelineB, 5);
active = sync_fence_count_with_status(merged, FENCE_STATUS_ACTIVE);
signaled = sync_fence_count_with_status(merged, FENCE_STATUS_SIGNALED);
ASSERT(active == 1 && signaled == 2,
"Fence did not signal properly!\n");
ret = sw_sync_timeline_inc(timelineC, 5);
active = sync_fence_count_with_status(merged, FENCE_STATUS_ACTIVE);
signaled = sync_fence_count_with_status(merged, FENCE_STATUS_SIGNALED);
ASSERT(active == 0 && signaled == 3,
"Fence did not signal properly!\n");
/* confirm you can successfully wait */
ret = sync_wait(merged, 100);
ASSERT(ret > 0, "Failure waiting on signaled fence\n");
sw_sync_fence_destroy(merged);
sw_sync_fence_destroy(fenceC);
sw_sync_fence_destroy(fenceB);
sw_sync_fence_destroy(fenceA);
sw_sync_timeline_destroy(timelineC);
sw_sync_timeline_destroy(timelineB);
sw_sync_timeline_destroy(timelineA);
return 0;
}
@@ -0,0 +1,67 @@
/*
* sync tests
* Copyright 2015-2016 Collabora Ltd.
*
* Based on the implementation from the Android Open Source Project,
*
* Copyright 2012 Google, Inc
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef SELFTESTS_SYNCTEST_H
#define SELFTESTS_SYNCTEST_H
#include <stdio.h>
#include "../kselftest.h"
#define ASSERT(cond, msg) do { \
if (!(cond)) { \
ksft_print_msg("[ERROR]\t%s", (msg)); \
return 1; \
} \
} while (0)
#define RUN_TEST(x) run_test((x), #x)
/* Allocation tests */
int test_alloc_timeline(void);
int test_alloc_fence(void);
int test_alloc_fence_negative(void);
/* Fence tests with one timeline */
int test_fence_one_timeline_wait(void);
int test_fence_one_timeline_merge(void);
/* Fence merge tests */
int test_fence_merge_same_fence(void);
/* Fence wait tests */
int test_fence_multi_timeline_wait(void);
/* Stress test - parallelism */
int test_stress_two_threads_shared_timeline(void);
/* Stress test - consumer */
int test_consumer_stress_multi_producer_single_consumer(void);
/* Stress test - merging */
int test_merge_stress_random_merge(void);
#endif