From 68da35270cd48047be0c60ee4cd012914cb2d3eb Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 2 Feb 2026 13:05:39 -0800 Subject: [PATCH 1/6] timer for windows and new cmake --- .github/workflows/cmake.yml | 6 ++-- CMakeLists.txt | 59 +++++++++++++++++++++------------ include/utils/Timer.h | 66 ++++++++++++++++++++++++++++--------- 3 files changed, 92 insertions(+), 39 deletions(-) diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index 30cc96d..0b354b0 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -11,17 +11,17 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-latest, macos-latest] + os: [ubuntu-latest, macos-latest, windows-latest] build_type: [Release, Debug] steps: - uses: actions/checkout@v3 - name: Configure CMake - run: cmake -B build -S . -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} + run: cmake -B build -S . -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DCMAKE_VERBOSE_MAKEFILE=ON - name: Build run: cmake --build build --config ${{ matrix.build_type }} - name: Run tests - run: ./build/all_tests + run: ./build/all_tests --verbose diff --git a/CMakeLists.txt b/CMakeLists.txt index 24f9139..da5f205 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,19 +20,23 @@ else() message(STATUS "Build type: ${CMAKE_BUILD_TYPE}") endif() -# Warning flags (always enabled) -add_compile_options( - -Wall # Enable most warnings - -Wextra # Extra warnings - -Wpedantic # Strict ISO C compliance - -Wshadow # Warn about variable shadowing - -Wformat=2 # Extra format string checks - -Wcast-qual # Warn about cast that removes qualifiers - -Wcast-align # Warn about pointer cast alignment issues - -Wunused # Warn about unused variables/functions - -Wdouble-promotion # Warn about float->double promotion - -Wnull-dereference # Warn about null pointer dereference -) +# Warning flags (compiler-specific) +if(MSVC) + add_compile_options(/W4 /WX) +else() + add_compile_options( + -Wall # Enable most warnings + -Wextra # Extra warnings + -Wpedantic # Strict ISO C compliance + -Wshadow # Warn about variable shadowing + -Wformat=2 # Extra format string checks + -Wcast-qual # Warn about cast that removes qualifiers + -Wcast-align # Warn about pointer cast alignment issues + -Wunused # Warn about unused variables/functions + -Wdouble-promotion # Warn about float->double promotion + -Wnull-dereference # Warn about null pointer dereference + ) +endif() # Include directories include_directories(${PROJECT_SOURCE_DIR}/include) @@ -43,15 +47,28 @@ file(GLOB_RECURSE SOURCES "src/*.c") # Create core library add_library(dnlp_diff ${SOURCES}) -target_link_libraries(dnlp_diff m) -# Config-specific compile options -target_compile_options(dnlp_diff PRIVATE - $<$:-g -O0> - $<$:-O3 -DNDEBUG> - $<$:-O2 -g -DNDEBUG> - $<$:-Os -DNDEBUG> -) +# Link math library (Unix/Linux only) +if(NOT MSVC) + target_link_libraries(dnlp_diff m) +endif() + +# Config-specific compile options (compiler-specific) +if(MSVC) + target_compile_options(dnlp_diff PRIVATE + $<$:/Od /Zi> + $<$:/O2 /DNDEBUG> + $<$:/O2 /Zi /DNDEBUG> + $<$:/Os /DNDEBUG> + ) +else() + target_compile_options(dnlp_diff PRIVATE + $<$:-g -O0> + $<$:-O3 -DNDEBUG> + $<$:-O2 -g -DNDEBUG> + $<$:-Os -DNDEBUG> + ) +endif() # This is needed for clock_gettime on Linux without compiler extensions if(CMAKE_SYSTEM_NAME STREQUAL "Linux") diff --git a/include/utils/Timer.h b/include/utils/Timer.h index c88c294..74a4dd8 100644 --- a/include/utils/Timer.h +++ b/include/utils/Timer.h @@ -1,25 +1,61 @@ +/* + * Copyright 2025 Daniel Cederberg + * + * This file is part of the PSLP project (LP Presolver). + * + * 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. + */ + #ifndef TIMER_H #define TIMER_H -#include "time.h" - +#if defined(_WIN32) || defined(_WIN64) +#include +typedef struct +{ + LARGE_INTEGER start, end; +} Timer; +static inline void clock_gettime_monotonic(Timer *timer, int is_start) +{ + if (is_start) + { + QueryPerformanceCounter(&timer->start); + } + else + { + QueryPerformanceCounter(&timer->end); + } +} +static inline double get_elapsed_seconds(const Timer *timer) +{ + LARGE_INTEGER freq; + QueryPerformanceFrequency(&freq); + return (double) (timer->end.QuadPart - timer->start.QuadPart) / + (double) freq.QuadPart; +} +#define clock_gettime(CLOCK, PTR) \ + clock_gettime_monotonic((Timer *) (PTR), ((PTR) == &((Timer *) (PTR))->start)) +#define GET_ELAPSED_SECONDS(timer) get_elapsed_seconds(&(timer)) +#else +#include typedef struct { struct timespec start, end; } Timer; -// Macro to compute elapsed time in seconds #define GET_ELAPSED_SECONDS(timer) \ - (((timer).end.tv_sec - (timer).start.tv_sec) + \ - ((double) ((timer).end.tv_nsec - (timer).start.tv_nsec) * 1e-9)) - -#define RUN_AND_TIME(func, timer, time_variable, result_var, ...) \ - do \ - { \ - clock_gettime(CLOCK_MONOTONIC, &timer.start); \ - (result_var) = func(__VA_ARGS__); \ - clock_gettime(CLOCK_MONOTONIC, &timer.end); \ - (time_variable) += GET_ELAPSED_SECONDS(timer); \ - } while (0) + ((double) ((timer).end.tv_sec - (timer).start.tv_sec) + \ + (double) ((timer).end.tv_nsec - (timer).start.tv_nsec) / 1e9) +#endif -#endif // TIMER_H +#endif // TIMER_H \ No newline at end of file From 293899f91ea209dcace427936f2006a571a19848 Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 2 Feb 2026 15:26:29 -0800 Subject: [PATCH 2/6] trigger workflow --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index da5f205..b0d91c0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,7 +33,7 @@ else() -Wcast-qual # Warn about cast that removes qualifiers -Wcast-align # Warn about pointer cast alignment issues -Wunused # Warn about unused variables/functions - -Wdouble-promotion # Warn about float->double promotion + -Wdouble-promotion # Warn about float to double promotion -Wnull-dereference # Warn about null pointer dereference ) endif() From 6a046c4e101930ef85b8b60ad93dc699ab4975fc Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 2 Feb 2026 15:38:42 -0800 Subject: [PATCH 3/6] windows Timer --- include/utils/Timer.h | 2 +- include/utils/Vec_macros.h | 24 +++++++++++++++--------- src/affine/add.c | 3 --- src/bivariate/const_scalar_mult.c | 3 --- src/elementwise_univariate/exp.c | 2 -- src/elementwise_univariate/log.c | 2 -- 6 files changed, 16 insertions(+), 20 deletions(-) diff --git a/include/utils/Timer.h b/include/utils/Timer.h index 74a4dd8..f967dc3 100644 --- a/include/utils/Timer.h +++ b/include/utils/Timer.h @@ -58,4 +58,4 @@ typedef struct (double) ((timer).end.tv_nsec - (timer).start.tv_nsec) / 1e9) #endif -#endif // TIMER_H \ No newline at end of file +#endif // TIMER_H diff --git a/include/utils/Vec_macros.h b/include/utils/Vec_macros.h index c3c0f14..714f3bb 100644 --- a/include/utils/Vec_macros.h +++ b/include/utils/Vec_macros.h @@ -24,17 +24,23 @@ #include #include +// Portable UNUSED macro +#if defined(_MSC_VER) +#define PSLP_UNUSED +#else +#define PSLP_UNUSED __attribute__((unused)) +#endif + // Macro to define a generic vector class #define DEFINE_VECTOR(TYPE, TYPE_NAME) \ typedef struct TYPE_NAME##Vec \ { \ TYPE *data; \ - size_t len; \ - size_t capacity; \ + int len; \ + int capacity; \ } TYPE_NAME##Vec; \ \ - __attribute__((unused)) static TYPE_NAME##Vec *TYPE_NAME##Vec_new( \ - size_t capacity) \ + PSLP_UNUSED static TYPE_NAME##Vec *TYPE_NAME##Vec_new(size_t capacity) \ { \ assert(capacity > 0); \ TYPE_NAME##Vec *vec = (TYPE_NAME##Vec *) malloc(sizeof(TYPE_NAME##Vec)); \ @@ -83,11 +89,11 @@ } \ \ static inline void TYPE_NAME##Vec_append_array(TYPE_NAME##Vec *vec, \ - const TYPE *values, size_t n) \ + const TYPE *values, int n) \ { \ if (vec->len + n > vec->capacity) \ { \ - size_t new_capacity = vec->capacity > 0 ? vec->capacity : 1; \ + int new_capacity = vec->capacity > 0 ? vec->capacity : 1; \ while (vec->len + n > new_capacity) \ { \ new_capacity *= 2; \ @@ -108,10 +114,10 @@ memcpy(vec->data + vec->len, values, n * sizeof(TYPE)); \ vec->len += n; \ } \ - __attribute__((unused)) static int TYPE_NAME##Vec_contains( \ - const TYPE_NAME##Vec *vec, TYPE value) \ + PSLP_UNUSED static int TYPE_NAME##Vec_contains(const TYPE_NAME##Vec *vec, \ + TYPE value) \ { \ - for (size_t i = 0; i < vec->len; ++i) \ + for (int i = 0; i < vec->len; ++i) \ { \ if (vec->data[i] == value) \ { \ diff --git a/src/affine/add.c b/src/affine/add.c index 8ebc2ef..2d1542f 100644 --- a/src/affine/add.c +++ b/src/affine/add.c @@ -101,8 +101,5 @@ expr *new_add(expr *left, expr *right) expr_retain(left); expr_retain(right); - // just for debugging, should be removed - strcpy(node->name, "add"); - return node; } diff --git a/src/bivariate/const_scalar_mult.c b/src/bivariate/const_scalar_mult.c index 44ba5f1..4898389 100644 --- a/src/bivariate/const_scalar_mult.c +++ b/src/bivariate/const_scalar_mult.c @@ -110,8 +110,5 @@ expr *new_const_scalar_mult(double a, expr *child) mult_node->a = a; expr_retain(child); - // just for debugging, should be removed - strcpy(node->name, "const_scalar_mult"); - return node; } diff --git a/src/elementwise_univariate/exp.c b/src/elementwise_univariate/exp.c index 165a658..fceac21 100644 --- a/src/elementwise_univariate/exp.c +++ b/src/elementwise_univariate/exp.c @@ -51,7 +51,5 @@ expr *new_exp(expr *child) node->local_jacobian = local_jacobian; node->local_wsum_hess = local_wsum_hess; - // just for debugging, should be removed - strcpy(node->name, "exp"); return node; } diff --git a/src/elementwise_univariate/log.c b/src/elementwise_univariate/log.c index 1315475..cea77d6 100644 --- a/src/elementwise_univariate/log.c +++ b/src/elementwise_univariate/log.c @@ -56,7 +56,5 @@ expr *new_log(expr *child) node->local_jacobian = local_jacobian; node->local_wsum_hess = local_wsum_hess; - // just for debugging, should be removed - strcpy(node->name, "log"); return node; } From f935c649e98560510acd289f3ab8c058adcdfbe4 Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 2 Feb 2026 15:42:29 -0800 Subject: [PATCH 4/6] replace size_t in ivec with int --- include/utils/Vec_macros.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/include/utils/Vec_macros.h b/include/utils/Vec_macros.h index 714f3bb..def45e4 100644 --- a/include/utils/Vec_macros.h +++ b/include/utils/Vec_macros.h @@ -40,7 +40,7 @@ int capacity; \ } TYPE_NAME##Vec; \ \ - PSLP_UNUSED static TYPE_NAME##Vec *TYPE_NAME##Vec_new(size_t capacity) \ + PSLP_UNUSED static TYPE_NAME##Vec *TYPE_NAME##Vec_new(int capacity) \ { \ assert(capacity > 0); \ TYPE_NAME##Vec *vec = (TYPE_NAME##Vec *) malloc(sizeof(TYPE_NAME##Vec)); \ @@ -74,7 +74,8 @@ { \ vec->capacity *= 2; \ assert(vec->capacity > 0); \ - TYPE *temp = (TYPE *) realloc(vec->data, vec->capacity * sizeof(TYPE)); \ + TYPE *temp = \ + (TYPE *) realloc(vec->data, (size_t) vec->capacity * sizeof(TYPE)); \ if (temp == NULL) \ { \ TYPE_NAME##Vec_free(vec); \ @@ -99,7 +100,8 @@ new_capacity *= 2; \ } \ \ - TYPE *temp = (TYPE *) realloc(vec->data, new_capacity * sizeof(TYPE)); \ + TYPE *temp = \ + (TYPE *) realloc(vec->data, (size_t) new_capacity * sizeof(TYPE)); \ if (temp == NULL) \ { \ TYPE_NAME##Vec_free(vec); \ @@ -111,7 +113,7 @@ vec->capacity = new_capacity; \ } \ \ - memcpy(vec->data + vec->len, values, n * sizeof(TYPE)); \ + memcpy(vec->data + vec->len, values, (size_t) n * sizeof(TYPE)); \ vec->len += n; \ } \ PSLP_UNUSED static int TYPE_NAME##Vec_contains(const TYPE_NAME##Vec *vec, \ From 55d06b57ae8d3c76e91b7e64c661dc149b83ae8b Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 2 Feb 2026 15:45:26 -0800 Subject: [PATCH 5/6] remove double return statement in test --- tests/wsum_hess/test_hstack.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/wsum_hess/test_hstack.h b/tests/wsum_hess/test_hstack.h index c802193..49c22b2 100644 --- a/tests/wsum_hess/test_hstack.h +++ b/tests/wsum_hess/test_hstack.h @@ -98,8 +98,6 @@ const char *test_wsum_hess_hstack() free_expr(hstack_node); return 0; - - return 0; } const char *test_wsum_hess_hstack_matrix() @@ -209,6 +207,4 @@ const char *test_wsum_hess_hstack_matrix() free_expr(hstack_node); return 0; - - return 0; } From 37de1027c2a94c18b8d20b9ea64b1d9cbae7c099 Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 2 Feb 2026 15:48:09 -0800 Subject: [PATCH 6/6] change workflow to use ctest --- .github/workflows/cmake.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index 0b354b0..87ef251 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -24,4 +24,4 @@ jobs: run: cmake --build build --config ${{ matrix.build_type }} - name: Run tests - run: ./build/all_tests --verbose + run: cd build && ctest -C ${{ matrix.build_type }} --verbose