blob: b866252dcef061e68c138a5e22a9012841906d6e [file] [log] [blame]
/*
* Copyright (c) 2008-2011 Apple Inc. All rights reserved.
*
* @APPLE_APACHE_LICENSE_HEADER_START@
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @APPLE_APACHE_LICENSE_HEADER_END@
*/
#ifdef __APPLE__
#include <mach/mach.h>
#include <mach/mach_time.h>
#endif
#include <dispatch/dispatch.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#ifdef __APPLE__
#include <TargetConditionals.h>
#endif
#include <bsdtests.h>
#include "dispatch_test.h"
#define COUNT 1000ul
#define LAPS 10ul
#if LENIENT_DEADLINES
#define ACCEPTABLE_LATENCY 10000
#elif TARGET_OS_EMBEDDED
#define ACCEPTABLE_LATENCY 3000
#else
#define ACCEPTABLE_LATENCY 1000
#endif
static dispatch_queue_t queues[COUNT];
static size_t lap_count_down = LAPS;
static size_t count_down;
static uint64_t start;
static mach_timebase_info_data_t tbi;
static void do_test(void);
static void
collect(void *context __attribute__((unused)))
{
uint64_t delta;
long double math;
size_t i;
if (--count_down) {
return;
}
delta = mach_absolute_time() - start;
delta *= tbi.numer;
delta /= tbi.denom;
math = delta;
math /= COUNT * COUNT * 2ul + COUNT * 2ul;
printf("lap: %zd\n", lap_count_down);
printf("count: %lu\n", COUNT);
printf("delta: %lu ns\n", (unsigned long)delta);
printf("math: %Lf ns / lap\n", math);
for (i = 0; i < COUNT; i++) {
dispatch_release(queues[i]);
}
// our malloc could be a lot better,
// this result is really a malloc torture test
test_long_less_than("Latency" , (long)math, ACCEPTABLE_LATENCY);
if (--lap_count_down) {
return do_test();
}
// give the threads some time to settle before test_stop() runs "leaks"
// ...also note, this is a total cheat. dispatch_after lets this
// thread go idle, so dispatch cleans up the continuations cache.
// Doign the "old style" sleep left that stuff around and leaks
// took a LONG TIME to complete. Long enough that the test harness
// decided to kill us.
dispatch_after_f(dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC), dispatch_get_main_queue(), NULL, test_stop_after_delay);
}
static void
pong(void *context)
{
dispatch_queue_t this_q = context;
size_t replies = (size_t)dispatch_get_context(this_q);
dispatch_set_context(this_q, (void *)--replies);
if (!replies) {
//printf("collect from: %s\n", dispatch_queue_get_label(dispatch_get_current_queue()));
dispatch_async_f(dispatch_get_main_queue(), NULL, collect);
}
}
static void
ping(void *context)
{
dispatch_queue_t reply_q = context;
dispatch_async_f(reply_q, reply_q, pong);
}
static void
start_node(void *context)
{
dispatch_queue_t this_q = context;
size_t i;
dispatch_set_context(this_q, (void *)COUNT);
for (i = 0; i < COUNT; i++) {
dispatch_async_f(queues[i], this_q, ping);
}
}
void
do_test(void)
{
dispatch_queue_t soup = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);
kern_return_t kr;
char buf[1000];
size_t i;
count_down = COUNT;
kr = mach_timebase_info(&tbi);
assert(kr == 0);
start = mach_absolute_time();
for (i = 0; i < COUNT; i++) {
snprintf(buf, sizeof(buf), "com.example.starfish-node#%zd", i);
queues[i] = dispatch_queue_create(buf, NULL);
dispatch_suspend(queues[i]);
dispatch_set_target_queue(queues[i], soup);
}
for (i = 0; i < COUNT; i++) {
dispatch_async_f(queues[i], queues[i], start_node);
}
for (i = 0; i < COUNT; i++) {
dispatch_resume(queues[i]);
}
}
int
main(void)
{
dispatch_test_start("Dispatch Starfish");
do_test();
dispatch_main();
}