diff --git a/Source/astcenccli_internal.h b/Source/astcenccli_internal.h index ee3a44e7..ea3ae384 100644 --- a/Source/astcenccli_internal.h +++ b/Source/astcenccli_internal.h @@ -397,6 +397,16 @@ void launch_threads( void (*func)(int, int, void*), void *payload); +/** + * @brief Set the current thread name to a string value. + * + * For portability strings should be no longer than 16 characters. + * + * @param name The thread name. + */ +void set_thread_name( + const char* name); + /** * @brief The main entry point. * diff --git a/Source/astcenccli_platform_dependents.cpp b/Source/astcenccli_platform_dependents.cpp index d5857f17..636b9163 100644 --- a/Source/astcenccli_platform_dependents.cpp +++ b/Source/astcenccli_platform_dependents.cpp @@ -1,6 +1,6 @@ // SPDX-License-Identifier: Apache-2.0 // ---------------------------------------------------------------------------- -// Copyright 2011-2023 Arm Limited +// Copyright 2011-2024 Arm Limited // // 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 @@ -38,7 +38,11 @@ #if defined(_WIN32) && !defined(__CYGWIN__) #define WIN32_LEAN_AND_MEAN +#define NOMINMAX #include +#include +#include +#include /** @brief Alias pthread_t to one of the internal Windows types. */ typedef HANDLE pthread_t; @@ -58,7 +62,7 @@ static int pthread_create( static_cast(attribs); LPTHREAD_START_ROUTINE func = reinterpret_cast(threadfunc); *thread = CreateThread(nullptr, 0, func, thread_arg, 0, nullptr); - + // Ensure we return 0 on success, non-zero on error if (*thread == NULL) { @@ -142,6 +146,24 @@ double get_time() return static_cast(ticks) / 1.0e7; } +/* See header for documentation */ +void set_thread_name( + const char* name +) { + // Names are limited to 16 characters + wchar_t wname [16] { 0 }; + size_t name_len = std::strlen(name); + size_t clamp_len = std::min(name_len, 15); + + // We know we only have basic 7-bit ASCII so just widen + for (size_t i = 0; i < clamp_len; i++) + { + wname[i] = static_cast(name[i]); + } + + SetThreadDescription(GetCurrentThread(), wname); +} + /* ============================================================================ Platform code for an platform using POSIX APIs. ============================================================================ */ @@ -165,6 +187,18 @@ double get_time() return static_cast(tv.tv_sec) + static_cast(tv.tv_usec) * 1.0e-6; } +/* See header for documentation */ +void set_thread_name( + const char* name +) { + // No standard mechanism, so be defensive here +#if defined(__linux__) + pthread_setname_np(pthread_self(), name); +#elif defined(__APPLE__) + pthread_setname_np(name); +#endif +} + #endif /** @@ -215,9 +249,9 @@ void launch_threads( } // Otherwise spawn worker threads - launch_desc *thread_descs = new launch_desc[thread_count]; + launch_desc *thread_descs = new launch_desc[thread_count]; int actual_thread_count { 0 }; - + for (int i = 0; i < thread_count; i++) { thread_descs[actual_thread_count].thread_count = thread_count; @@ -230,7 +264,7 @@ void launch_threads( &(thread_descs[actual_thread_count].thread_handle), nullptr, launch_threads_helper, - reinterpret_cast(thread_descs + actual_thread_count)); + reinterpret_cast(thread_descs + actual_thread_count)); // Track how many threads we actually created if (!error) @@ -248,7 +282,7 @@ void launch_threads( // If we did not create thread_count threads then emit a warning if (actual_thread_count != thread_count) - { + { int log_count = actual_thread_count == 0 ? 1 : actual_thread_count; const char* log_s = log_count == 1 ? "" : "s"; printf("WARNING: %s using %d thread%s due to thread creation error\n\n", diff --git a/Source/astcenccli_toplevel.cpp b/Source/astcenccli_toplevel.cpp index dd0941b6..cfac9c57 100644 --- a/Source/astcenccli_toplevel.cpp +++ b/Source/astcenccli_toplevel.cpp @@ -232,6 +232,10 @@ static void compression_workload_runner( ) { (void)thread_count; + char name[16] { 0 }; + std::snprintf(name, 16, "astc workc %d", thread_id); + set_thread_name(name); + compression_workload* work = static_cast(payload); astcenc_error error = astcenc_compress_image( work->context, work->image, &work->swizzle, @@ -259,6 +263,10 @@ static void decompression_workload_runner( ) { (void)thread_count; + char name[16] { 0 }; + std::snprintf(name, 16, "astc workd %d", thread_id); + set_thread_name(name); + decompression_workload* work = static_cast(payload); astcenc_error error = astcenc_decompress_image( work->context, work->data, work->data_len, @@ -1881,10 +1889,13 @@ static void print_diagnostic_images( * * @return 0 on success, non-zero otherwise. */ -int astcenc_main( +int +astcenc_main( int argc, char **argv ) { + set_thread_name("astc main"); + #if ASTCENC_SVE != 0 // Do this check here because is needs SVE instructions so cannot be in // the veneer check which is compiled as stock Armv8. We know we have SVE