Some checks failed
Docker. / Ubuntu (push) Has been cancelled
User-agent updater. / User-agent (push) Failing after 15s
Lock Threads / lock (push) Failing after 10s
Waiting for answer. / waiting-for-answer (push) Failing after 22s
Close stale issues and PRs / stale (push) Successful in 13s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
223 lines
5.0 KiB
C
223 lines
5.0 KiB
C
/*
|
|
* 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@
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <dispatch/dispatch.h>
|
|
#include <dispatch/private.h>
|
|
#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
|
|
#include <unistd.h>
|
|
#ifdef __ANDROID__
|
|
#include <linux/sysctl.h>
|
|
#else
|
|
#if !defined(__linux__)
|
|
#include <sys/sysctl.h>
|
|
#endif
|
|
#endif /* __ANDROID__ */
|
|
#endif
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
#ifdef __APPLE__
|
|
#include <TargetConditionals.h>
|
|
#endif
|
|
#include <sys/types.h>
|
|
|
|
#include <bsdtests.h>
|
|
#include "dispatch_test.h"
|
|
|
|
static volatile int done;
|
|
|
|
#ifdef DISPATCH_QUEUE_PRIORITY_BACKGROUND // <rdar://problem/7439794>
|
|
#define USE_BACKGROUND_PRIORITY 1
|
|
#else
|
|
#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN
|
|
#endif
|
|
|
|
#define QUEUE_PRIORITY_PTHREAD INT_MAX
|
|
|
|
#if DISPATCH_API_VERSION < 20100518 // <rdar://problem/7790099>
|
|
#define DISPATCH_QUEUE_CONCURRENT NULL
|
|
#endif
|
|
|
|
#if TARGET_OS_EMBEDDED
|
|
#define LOOP_COUNT 5000000
|
|
const int importance = 24; // priority 55
|
|
#else
|
|
#define LOOP_COUNT 100000000
|
|
const int importance = 4; // priority 35
|
|
#endif
|
|
|
|
char *labels[] = { "BACKGROUND", "LOW", "DEFAULT", "HIGH", };
|
|
int levels[] = {
|
|
DISPATCH_QUEUE_PRIORITY_BACKGROUND, DISPATCH_QUEUE_PRIORITY_LOW,
|
|
DISPATCH_QUEUE_PRIORITY_DEFAULT, DISPATCH_QUEUE_PRIORITY_HIGH,
|
|
};
|
|
#define PRIORITIES (sizeof(levels)/sizeof(*levels))
|
|
|
|
static union {
|
|
long count;
|
|
char padding[64];
|
|
} counts[PRIORITIES];
|
|
|
|
static volatile long iterations;
|
|
static long total;
|
|
static size_t prio0, priorities = PRIORITIES;
|
|
|
|
static int
|
|
n_blocks(void)
|
|
{
|
|
static dispatch_once_t pred;
|
|
static int n;
|
|
dispatch_once(&pred, ^{
|
|
#ifdef __linux__
|
|
n = (int)sysconf(_SC_NPROCESSORS_CONF);
|
|
#elif defined(_WIN32)
|
|
SYSTEM_INFO si;
|
|
GetSystemInfo(&si);
|
|
n = (int)si.dwNumberOfProcessors;
|
|
#else
|
|
size_t l = sizeof(n);
|
|
int rc = sysctlbyname("hw.ncpu", &n, &l, NULL, 0);
|
|
assert(rc == 0);
|
|
#endif
|
|
n *= 32;
|
|
});
|
|
return n;
|
|
}
|
|
|
|
static void
|
|
histogram(void)
|
|
{
|
|
long completed = 0;
|
|
size_t x, y, i;
|
|
printf("\n");
|
|
for (y = prio0; y < prio0 + priorities; ++y) {
|
|
printf("%s: %ld\n", labels[y], counts[y].count);
|
|
completed += counts[y].count;
|
|
|
|
double fraction = (double)counts[y].count / (double)n_blocks();
|
|
double value = fraction * (double)80;
|
|
for (x = 0; x < 80; ++x) {
|
|
printf("%s", (value > x) ? "*" : " ");
|
|
}
|
|
printf("\n");
|
|
}
|
|
|
|
test_long("blocks completed", completed, total);
|
|
for (i = prio0; i < prio0 + priorities; i++) {
|
|
if (levels[i] == DISPATCH_QUEUE_PRIORITY_HIGH) {
|
|
test_long_less_than_or_equal("high priority precedence",
|
|
counts[i-2].count, counts[i].count);
|
|
}
|
|
#if USE_BACKGROUND_PRIORITY
|
|
if (levels[i] == DISPATCH_QUEUE_PRIORITY_BACKGROUND) {
|
|
test_long_less_than_or_equal("background priority precedence",
|
|
counts[i].count, counts[i+2].count);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
static void
|
|
cpubusy(void* context)
|
|
{
|
|
if (done) return;
|
|
size_t idx;
|
|
for (idx = 0; idx < LOOP_COUNT; ++idx) {
|
|
if (done) break;
|
|
}
|
|
|
|
volatile long *count = context;
|
|
long iterdone = __sync_sub_and_fetch(&iterations, 1);
|
|
|
|
if (iterdone >= 0) {
|
|
__sync_add_and_fetch(count, 1);
|
|
if (!iterdone) {
|
|
__sync_add_and_fetch(&done, 1);
|
|
usleep(100000);
|
|
histogram();
|
|
dispatch_time_t delay = DISPATCH_TIME_NOW;
|
|
dispatch_after(delay, dispatch_get_main_queue(), ^{
|
|
test_stop();
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
submit_work(dispatch_queue_t queue, void* context)
|
|
{
|
|
int i;
|
|
|
|
for (i = n_blocks(); i; --i) {
|
|
dispatch_async_f(queue, context, cpubusy);
|
|
}
|
|
|
|
}
|
|
|
|
int
|
|
main(int argc __attribute__((unused)), char* argv[] __attribute__((unused)))
|
|
{
|
|
dispatch_queue_t q[PRIORITIES];
|
|
size_t i;
|
|
|
|
#if !USE_BACKGROUND_PRIORITY
|
|
prio0++;
|
|
priorities--;
|
|
#endif
|
|
|
|
iterations = total = ((int)priorities * n_blocks()) / 2;
|
|
|
|
#if USE_SET_TARGET_QUEUE
|
|
dispatch_test_start("Dispatch Priority (Set Target Queue)");
|
|
#else
|
|
dispatch_test_start("Dispatch Priority");
|
|
#endif
|
|
|
|
for (i = prio0; i < prio0 + priorities; i++) {
|
|
dispatch_queue_t rq = dispatch_get_global_queue(levels[i], 0);
|
|
#if USE_SET_TARGET_QUEUE
|
|
q[i] = dispatch_queue_create(labels[i], DISPATCH_QUEUE_CONCURRENT);
|
|
test_ptr_notnull("q[i]", q[i]);
|
|
assert(q[i]);
|
|
dispatch_suspend(q[i]);
|
|
dispatch_set_target_queue(q[i], rq);
|
|
if (DISPATCH_QUEUE_CONCURRENT != NULL) {
|
|
dispatch_queue_set_width(q[i], LONG_MAX);
|
|
}
|
|
dispatch_release(rq);
|
|
#else
|
|
q[i] = rq;
|
|
#endif
|
|
}
|
|
|
|
for (i = prio0; i < prio0 + priorities; i++) {
|
|
submit_work(q[i], &counts[i].count);
|
|
}
|
|
|
|
for (i = prio0; i < prio0 + priorities; i++) {
|
|
dispatch_resume(q[i]);
|
|
dispatch_release(q[i]);
|
|
}
|
|
|
|
dispatch_main();
|
|
|
|
return 0;
|
|
}
|