| /* |
| * 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(); |
| } |