/*
任务4(必做）：编译、测试和运行示例程序psum64.c
1）测量线程数为1、2、4、8、16时程序的执行时间，计算加速比和效率，并做出解释。
2）改写该程序psum64.c,保存为task64.c，实现计算0²+1²+…+(n-1)²功能。
*/

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

#define MAXTHREADS 16

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

unsigned long long psum64[MAXTHREADS];
unsigned long long nelems_per_thread;

int main(int argc, char **argv)
{
    unsigned long long i, nelems, log_nelems, nthreads, result = 0;
    pthread_t tid[MAXTHREADS];
    int myid[MAXTHREADS];

    if (argc != 3)
    {
        printf("Usage: %s <nthreads> <log_nelems>\n", argv[0]);
        exit(0);
    }
    nthreads = atoi(argv[1]);
    log_nelems = atoi(argv[2]);
    nelems = (1LL << log_nelems);
    nelems_per_thread = nelems / nthreads;

    double t_start = get_time();
    for (i = 0; i < nthreads; i++)
    {
        myid[i] = i;
        pthread_create(&tid[i], NULL, sum, &myid[i]);
    }

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

    for (i = 0; i < nthreads; i++)
    {
        result += psum64[i];
    }

    /* 验证公式: 0²+1²+...+(n-1)² = (n-1)*n*(2n-1)/6 */
    if (result == (nelems * (nelems - 1) * (2 * nelems - 1)) / 6)
    {
        printf("Correct result: %llu\n", result);
    }
    else
    {
        printf("Wrong result: %llu\n", result);
    }
    double t_end = get_time();
    printf("Time taken: %f seconds\n", t_end - t_start);

    exit(0);
}

void *sum(void *vargp)
{
    int myid = *((int *)vargp);
    unsigned long long begin = myid * nelems_per_thread;
    unsigned long long end = begin + nelems_per_thread;
    unsigned long long i, lsum = 0;

    for (i = begin; i < end; i++)
    {
        lsum += i * i;
    }

    psum64[myid] = lsum;
    return NULL;
}
