#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/time.h>

#define MAX_THREADS 64
#define N 1000000000LL

long long global_sum = 0;
long long nelems_per_thread;
pthread_mutex_t mutex;

void *sum_thread(void *arg) {
    long long start = *(long long *)arg;
    long long local_sum = 0;
    long long end = start + nelems_per_thread;
    if (end > N) end = N;
    for (long long i = start; i < end; i++) {
        local_sum += i;
    }
    pthread_mutex_lock(&mutex);
    global_sum += local_sum;
    pthread_mutex_unlock(&mutex);
    return NULL;
}

double get_time() {
    struct timeval tv;
    gettimeofday(&tv, NULL);
    return tv.tv_sec + tv.tv_usec / 1000000.0;
}

int main(int argc, char *argv[]) {
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <num_threads>\n", argv[0]);
        return 1;
    }

    int nthreads = atoi(argv[1]);
    if (nthreads > MAX_THREADS) nthreads = MAX_THREADS;

    nelems_per_thread = N / nthreads;
    pthread_mutex_init(&mutex, NULL);

    pthread_t threads[MAX_THREADS];
    long long starts[MAX_THREADS];

    double t_start = get_time();

    for (int i = 0; i < nthreads; i++) {
        starts[i] = i * nelems_per_thread;
        pthread_create(&threads[i], NULL, sum_thread, &starts[i]);
    }

    for (int i = 0; i < nthreads; i++) {
        pthread_join(threads[i], NULL);
    }

    double t_end = get_time();
    double elapsed = t_end - t_start;

    printf("Threads: %d, Sum: %lld, Time: %.6f s\n", nthreads, global_sum, elapsed);

    pthread_mutex_destroy(&mutex);
    return 0;
}
