From a0d4f0646ff1cea96dfa9814276210cec9f4eba2 Mon Sep 17 00:00:00 2001 From: Oliver Nguyen Date: Mon, 9 Dec 2019 16:36:08 -0800 Subject: [PATCH] Add cross-process coverage flushing for the LLVM toolchain. Bug: 143977934 Test: Build with native coverage Test: kill -37 and check for coverage in /data/misc/trace Change-Id: Iadf93e62d92dc35cdaa35162ca4a75d26190db85 --- toolchain-extras/Android.bp | 36 ++++++++++++++ toolchain-extras/profile-clang-extras-test.cpp | 36 ++++++++++++++ toolchain-extras/profile-clang-extras.cpp | 68 ++++++++++++++++++++++++++ toolchain-extras/profile-extras-test.cpp | 2 +- toolchain-extras/profile-extras.cpp | 4 +- toolchain-extras/profile-extras.h | 2 +- 6 files changed, 144 insertions(+), 4 deletions(-) create mode 100644 toolchain-extras/profile-clang-extras-test.cpp create mode 100644 toolchain-extras/profile-clang-extras.cpp diff --git a/toolchain-extras/Android.bp b/toolchain-extras/Android.bp index 7cc97344..d9bf6a41 100644 --- a/toolchain-extras/Android.bp +++ b/toolchain-extras/Android.bp @@ -35,6 +35,42 @@ cc_library_static { sdk_version: "minimum", } +cc_defaults { + name: "libprofile-clang-defaults", + srcs: [ + "profile-clang-extras.cpp", + ], + native_coverage: false, +} + +cc_library_static { + name: "libprofile-clang-extras", + defaults: ["libprofile-clang-defaults"], + + native_bridge_supported: true, + vendor_available: true, + vndk: { + enabled: true, + }, + recovery_available: true, + + stl: "none", + system_shared_libs: [], + header_libs: ["libc_headers"], +} + +cc_library_static { + name: "libprofile-clang-extras_ndk", + defaults: ["libprofile-clang-defaults"], + native_bridge_supported: true, + vendor_available: true, + vndk: { + enabled: true, + }, + + sdk_version: "minimum", +} + cc_test { name: "libprofile-extras-test", srcs: [ diff --git a/toolchain-extras/profile-clang-extras-test.cpp b/toolchain-extras/profile-clang-extras-test.cpp new file mode 100644 index 00000000..2bb7bdbb --- /dev/null +++ b/toolchain-extras/profile-clang-extras-test.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * 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. + */ + +#include +#include "profile-extras.h" + +static int flush_count = 0; + +extern "C" { +int __llvm_profile_write_file() { + flush_count++; + return 0; +} +} + +TEST(profile_extras, smoke) { + flush_count = 0; + + ASSERT_EQ(0, flush_count); + kill(getpid(), GCOV_FLUSH_SIGNAL); + sleep(2); + ASSERT_EQ(1, flush_count); +} diff --git a/toolchain-extras/profile-clang-extras.cpp b/toolchain-extras/profile-clang-extras.cpp new file mode 100644 index 00000000..89c18b2a --- /dev/null +++ b/toolchain-extras/profile-clang-extras.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * 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. + */ + +#include +#include +#include + +#include "profile-extras.h" + +extern "C" { + +static sighandler_t chained_signal_handler = SIG_ERR; + +int __llvm_profile_write_file(void); + +static void llvm_signal_handler(__unused int signum) { + __llvm_profile_write_file(); + + if (chained_signal_handler != SIG_ERR && + chained_signal_handler != SIG_IGN && + chained_signal_handler != SIG_DFL) { + (chained_signal_handler)(signum); + } +} + +__attribute__((weak)) int init_profile_extras_once = 0; + +// Initialize libprofile-extras: +// - Install a signal handler that triggers __llvm_profile_write_file on . +// +// We want this initializer to run during load time. +// +// Just marking init_profile_extras() with __attribute__((constructor)) isn't +// enough since the linker drops it from its output since no other symbol from +// this static library is referenced. +// +// We force the linker to include init_profile_extras() by passing +// '-uinit_profile_extras' to the linker (in build/soong). +__attribute__((constructor)) int init_profile_extras(void) { + if (init_profile_extras_once) + return 0; + init_profile_extras_once = 1; + + if (chained_signal_handler != SIG_ERR) { + return -1; + } + sighandler_t ret1 = signal(COVERAGE_FLUSH_SIGNAL, llvm_signal_handler); + if (ret1 == SIG_ERR) { + return -1; + } + chained_signal_handler = ret1; + + return 0; +} +} diff --git a/toolchain-extras/profile-extras-test.cpp b/toolchain-extras/profile-extras-test.cpp index 5e48a646..0e52f15c 100644 --- a/toolchain-extras/profile-extras-test.cpp +++ b/toolchain-extras/profile-extras-test.cpp @@ -34,7 +34,7 @@ TEST(profile_extras, smoke) { flush_count = 0; ASSERT_EQ(0, flush_count); - kill(getpid(), GCOV_FLUSH_SIGNAL); + kill(getpid(), COVERAGE_FLUSH_SIGNAL); sleep(2); ASSERT_EQ(1, flush_count); diff --git a/toolchain-extras/profile-extras.cpp b/toolchain-extras/profile-extras.cpp index 7d78a0a5..d2a541cd 100644 --- a/toolchain-extras/profile-extras.cpp +++ b/toolchain-extras/profile-extras.cpp @@ -92,7 +92,7 @@ static size_t prop_watch_num_disabled_procs = \ __attribute__((weak)) int init_profile_extras_once = 0; // Initialize libprofile-extras: -// - Install a signal handler that triggers __gcov_flush on . +// - Install a signal handler that triggers __gcov_flush on . // - Create a thread that calls __gcov_flush when sysprop // transistions to "1" after a transistion to "0". // @@ -113,7 +113,7 @@ __attribute__((constructor)) int init_profile_extras(void) { if (chained_gcov_signal_handler != SIG_ERR) { return -1; } - sighandler_t ret1 = signal(GCOV_FLUSH_SIGNAL, gcov_signal_handler); + sighandler_t ret1 = signal(COVERAGE_FLUSH_SIGNAL, gcov_signal_handler); if (ret1 == SIG_ERR) { return -1; } diff --git a/toolchain-extras/profile-extras.h b/toolchain-extras/profile-extras.h index 3e217eaf..5b20618e 100644 --- a/toolchain-extras/profile-extras.h +++ b/toolchain-extras/profile-extras.h @@ -16,4 +16,4 @@ #include -#define GCOV_FLUSH_SIGNAL (__SIGRTMIN + 5) +#define COVERAGE_FLUSH_SIGNAL (__SIGRTMIN + 5) -- 2.11.0