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
204 lines
5.2 KiB
C
204 lines
5.2 KiB
C
/*
|
|
* Copyright (c) 2010-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 <sys/event.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
|
|
#include <unistd.h>
|
|
#endif
|
|
#ifdef __APPLE__
|
|
#include <libkern/OSAtomic.h>
|
|
#endif
|
|
#include <assert.h>
|
|
#ifdef __ANDROID__
|
|
#include <linux/sysctl.h>
|
|
#else
|
|
#if !defined(__linux__)
|
|
#include <sys/sysctl.h>
|
|
#endif
|
|
#endif /* __ANDROID__ */
|
|
#include <stdarg.h>
|
|
#include <time.h>
|
|
|
|
#include <dispatch/dispatch.h>
|
|
#include <dispatch/private.h>
|
|
|
|
#include <bsdtests.h>
|
|
#include "dispatch_test.h"
|
|
|
|
#if defined(DISPATCH_SOURCE_TYPE_VM) && defined(NOTE_VM_PRESSURE)
|
|
|
|
#if TARGET_OS_EMBEDDED
|
|
#define ALLOC_SIZE ((size_t)(1024*1024*1ul)) // 1MB
|
|
#define NOTIFICATIONS 1
|
|
#else
|
|
#define ALLOC_SIZE ((size_t)(1024*1024*20ul)) // 20MB
|
|
#define NOTIFICATIONS 2
|
|
#endif
|
|
#define pg2mb(p) ((p) * ALLOC_SIZE/(1024*1024))
|
|
#ifdef __LP64__
|
|
#define MAXMEM ((size_t)SIZE_MAX)
|
|
#else
|
|
#define MAXMEM ((size_t)(3200ul*1024*1024)) // 3200MB
|
|
#endif
|
|
|
|
static char **pages;
|
|
static volatile int32_t handler_call_count;
|
|
static volatile int32_t page_count;
|
|
static int32_t max_page_count;
|
|
static dispatch_source_t vm_source;
|
|
static dispatch_queue_t vm_queue;
|
|
static time_t initial;
|
|
static int interval = 16;
|
|
|
|
#define log_msg(msg, ...) \
|
|
do { \
|
|
fprintf(stderr, "[%2ds] " msg, (int)(time(NULL) - initial), ##__VA_ARGS__);\
|
|
} while (0)
|
|
|
|
static bool
|
|
dispatch_test_check_evfilt_vm(void)
|
|
{
|
|
int kq = kqueue();
|
|
assert(kq != -1);
|
|
struct kevent ke = {
|
|
.filter = EVFILT_VM,
|
|
.flags = EV_ADD|EV_ENABLE|EV_RECEIPT,
|
|
.fflags = NOTE_VM_PRESSURE,
|
|
};
|
|
int r = kevent(kq, &ke, 1, &ke, 1, NULL);
|
|
close(kq);
|
|
return !(r > 0 && ke.flags & EV_ERROR && ke.data == ENOTSUP);
|
|
}
|
|
|
|
static void
|
|
cleanup(void)
|
|
{
|
|
dispatch_source_cancel(vm_source);
|
|
dispatch_release(vm_source);
|
|
dispatch_release(vm_queue);
|
|
|
|
int32_t pc = 0, i;
|
|
for (i = 0; i < max_page_count; ++i) {
|
|
if (pages[i]) {
|
|
pc++;
|
|
free(pages[i]);
|
|
}
|
|
}
|
|
if (pc) {
|
|
log_msg("Freed %ldMB\n", pg2mb(pc));
|
|
}
|
|
free(pages);
|
|
test_stop();
|
|
}
|
|
|
|
int
|
|
main(void)
|
|
{
|
|
dispatch_test_start("Dispatch VM Pressure test"); // rdar://problem/7000945
|
|
if (!dispatch_test_check_evfilt_vm()) {
|
|
test_skip("EVFILT_VM not supported");
|
|
test_stop();
|
|
return 0;
|
|
}
|
|
initial = time(NULL);
|
|
uint64_t memsize;
|
|
#ifdef __linux__
|
|
memsize = sysconf(_SC_PAGESIZE) * sysconf(_SC_PHYS_PAGES);
|
|
#else
|
|
size_t s = sizeof(memsize);
|
|
int rc = sysctlbyname("hw.memsize", &memsize, &s, NULL, 0);
|
|
assert(rc == 0);
|
|
#endif
|
|
max_page_count = MIN(memsize, MAXMEM) / ALLOC_SIZE;
|
|
pages = calloc(max_page_count, sizeof(char*));
|
|
|
|
vm_queue = dispatch_queue_create("VM Pressure", NULL);
|
|
vm_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_VM, 0,
|
|
DISPATCH_VM_PRESSURE, vm_queue);
|
|
dispatch_source_set_event_handler(vm_source, ^{
|
|
if (!page_count) {
|
|
// Too much memory pressure already to start the test
|
|
test_skip("Memory pressure at start of test");
|
|
cleanup();
|
|
}
|
|
if (OSAtomicIncrement32Barrier(&handler_call_count) != NOTIFICATIONS) {
|
|
log_msg("Ignoring vm pressure notification\n");
|
|
interval = 1;
|
|
return;
|
|
}
|
|
test_long("dispatch_source_get_data()",
|
|
dispatch_source_get_data(vm_source), NOTE_VM_PRESSURE);
|
|
int32_t i, pc = page_count + 1;
|
|
for (i = 0; i < pc && pages[i]; ++i) {
|
|
free(pages[i]);
|
|
pages[i] = NULL;
|
|
}
|
|
log_msg("Freed %ldMB\n", pg2mb(i));
|
|
});
|
|
dispatch_resume(vm_source);
|
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC),
|
|
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
|
while (handler_call_count < NOTIFICATIONS &&
|
|
page_count < max_page_count) {
|
|
void *p = valloc(ALLOC_SIZE);
|
|
if (!p) {
|
|
break;
|
|
}
|
|
bzero(p, ALLOC_SIZE);
|
|
pages[page_count] = p;
|
|
if (!(OSAtomicIncrement32Barrier(&page_count) % interval)) {
|
|
log_msg("Allocated %ldMB\n", pg2mb(page_count));
|
|
usleep(200000);
|
|
}
|
|
}
|
|
if (page_count % interval) {
|
|
log_msg("Allocated %ldMB\n", pg2mb(page_count));
|
|
}
|
|
if (handler_call_count < NOTIFICATIONS) {
|
|
// Cannot allocate enough memory for test (e.g. on 32 bit)
|
|
test_skip("Cannot allocate enough memory for test");
|
|
dispatch_async(vm_queue, ^{cleanup();});
|
|
return;
|
|
}
|
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC),
|
|
vm_queue, ^{
|
|
test_long_greater_than_or_equal("VM Pressure fired",
|
|
handler_call_count, NOTIFICATIONS);
|
|
test_long_less_than("VM Pressure stopped firing",
|
|
handler_call_count, 4);
|
|
cleanup();
|
|
});
|
|
});
|
|
dispatch_main();
|
|
return 0;
|
|
}
|
|
#else //DISPATCH_SOURCE_TYPE_VM
|
|
int
|
|
main(void)
|
|
{
|
|
dispatch_test_start("Dispatch VM Pressure test"
|
|
" - No DISPATCH_SOURCE_TYPE_VM");
|
|
test_stop();
|
|
return 0;
|
|
}
|
|
#endif //DISPATCH_SOURCE_TYPE_VM
|