// (c) 2007 Abdulla Abdurakhmanov
// C++
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//

#pragma once


#define WIN32_LEAN_AND_MEAN        // Exclude rarely-used stuff from Windows headers
#include <stdio.h>
#include <time.h>
#include <string>

#ifndef WIN32
#include <sys/types.h>
#include <sys/socket.h>    
#define SOCKET int
#define WORD unsigned int
#define INADDR_NONE (in_addr_t)(-1)
#define INVALID_SOCKET -1
#define SOCKET_ERROR -1
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>     
#include <sys/time.h>

extern long GetTickCount(void);
//#define GetTickCount gethrtime
#else
#include <tchar.h>
#include <windows.h>
#include <winsock2.h>
#endif


// TestPerf.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

class MyParentClass
{   
    private:
        std::string pField;
        std::string cField;
        long pField2;
    public:
        MyParentClass() : pField("Hello"), pField2 (0xFF)
        {
            //pField = "Hello ";
            //pField2 = 0xFF;
        }

        virtual std::string vMethod(const std::string& val) = 0;

        std::string sMethod(const std::string& val)
        {
            cField = pField + val;
            return cField;
        }

        long lMethod (long v)
        {
            return v*10;
        }

        virtual long vlMethod(long val) = 0;

        void l2Method (long r)
        {
            pField2 = r;
        }

};

class MyClass : public MyParentClass
{   
    public:
        virtual std::string vMethod(const std::string& val)
        {
            return this->sMethod(val);
        }

        virtual long vlMethod (long v)
        {
            return v*10;
        }
};

const int OBJ_COUNT = 1000000;

void DieWithError(const std::string& err) 
{
    printf("Err: %s\n",err.c_str());
    exit(-1);
}



SOCKET clientSocket;

void createSocketClient()
{
#ifdef WIN32
    WORD wVersionRequested;
    WSADATA wsaData;
    int err;
     
    wVersionRequested = MAKEWORD( 2, 2 );
     
    err = WSAStartup( wVersionRequested, &wsaData );
    if ( err != 0 ) {
        /* Tell the user that we could not find a usable */
        /* WinSock DLL.                                  */
        return;
    }
#endif
   
    u_long nRemoteAddr = inet_addr("127.0.0.1");
    if (nRemoteAddr == INADDR_NONE) {
        // pcHost isn't a dotted IP, so resolve it through DNS
        hostent* pHE = gethostbyname("localhost");
        if (pHE == 0) {
            DieWithError("Unable to connect!");
        }
        nRemoteAddr = *((u_long*)pHE->h_addr_list[0]);
    }
    clientSocket = socket(AF_INET, SOCK_STREAM, 0);
    if (clientSocket != INVALID_SOCKET) {
        sockaddr_in sinRemote;
        sinRemote.sin_family = AF_INET;
        sinRemote.sin_addr.s_addr = nRemoteAddr;
        sinRemote.sin_port = htons( 5555 );
        if (connect(clientSocket, (sockaddr*)&sinRemote, sizeof(sockaddr_in)) ==
                SOCKET_ERROR) {
            clientSocket = INVALID_SOCKET;
        }
    }
}


void stopSocketClient()
{
#ifdef WIN32
    closesocket(clientSocket);
    WSACleanup();
#else
    shutdown(clientSocket, SHUT_RDWR);
    close(clientSocket);
#endif
}


void networkTest(int count, int pktSize)
{
    printf("Network perf test. Iter count: %d. Packet size: %d\n", count, pktSize);
    createSocketClient();
    char* buf = new char[pktSize];
    memset(buf,0xFF,pktSize);
    int totalBytesSnt = 0, totalBytesRcv = 0;
    long startTime = GetTickCount();
    for(int i=0;i<count;i++)
    {
        int bt = send(clientSocket, buf, pktSize, 0);
        if (bt > 0 ) {
            totalBytesSnt += bt;
        }
        else
            printf("Write error!\n");

        bt = recv(clientSocket, buf, pktSize, 0);
        if (bt > 0 )
            totalBytesRcv += bt;
        else
            printf("Read error!\n");
    }
    long endTime = GetTickCount();
    printf("Elapsed time for network perf is %.3f\n",
        ((endTime-startTime)/1000.0)
    );
    stopSocketClient();
    delete[] buf;
}

int main(int argc, char* argv[])
{
    printf("Creating %d objects\n", OBJ_COUNT);
    long startTime = GetTickCount();
    MyParentClass** objs = new MyParentClass* [OBJ_COUNT];
    for(int i=0;i<OBJ_COUNT;i++)
    {
        objs[i] = new MyClass();
    }
    long endTime = GetTickCount();
    printf("Elapsed time for %d objects: %.3f\n", OBJ_COUNT, (endTime-startTime)/1000.0);

    printf("Calling a usual non-virtual method on %d objects\n", OBJ_COUNT);
    startTime = GetTickCount();
    for(int i=0;i<OBJ_COUNT;i++)
    {
        for(int j=0;j<10;j++)
            objs[i]->sMethod(objs[i]->sMethod("Vasya"));
    }
    endTime = GetTickCount();
    printf("Elapsed time for %d objects: %.3f\n", OBJ_COUNT, (endTime-startTime)/1000.0);

    printf("Calling a virtual method on %d objects\n", OBJ_COUNT);
    startTime = GetTickCount();
    for(int i=0;i<OBJ_COUNT;i++)
    {
        for(int j=0;j<10;j++)
            objs[i]->vMethod(objs[i]->vMethod("Vasya"));
    }
    endTime = GetTickCount();
    printf("Elapsed time for %d objects: %.3f\n", OBJ_COUNT, (endTime-startTime)/1000.0);

    printf("Calling a usual non-virtual method for long on %d objects\n", OBJ_COUNT);
    startTime = GetTickCount();
    for(int i=0;i<OBJ_COUNT;i++)
    {
        for(int j=0;j<500;j++)
        {
            objs[i]->l2Method( objs[i]->lMethod(j) );
        }
    }
    endTime = GetTickCount();
    printf("Elapsed time for %d objects: %.3f\n", OBJ_COUNT, (endTime-startTime)/1000.0);

    printf("Calling a virtual method for long on %d objects\n", OBJ_COUNT);
    startTime = GetTickCount();
    for(int i=0;i<OBJ_COUNT;i++)
    {
        for(int j=0;j<500;j++)
        {
            objs[i]->l2Method( objs[i]->vlMethod(j) );
        }
    }
    endTime = GetTickCount();
    printf("Elapsed time for %d objects: %.3f\n", OBJ_COUNT, (endTime-startTime)/1000.0);

    networkTest(10000, 256);
    networkTest(100000, 256);
    networkTest(1000000, 256);
    networkTest(50000, 512);
    //for(int
    //for ( int i = 0; i <
    return 0;
}

#ifndef WIN32
long GetTickCount(void) {
    struct timeval now;
    gettimeofday(&now, NULL);
    return now.tv_sec*1000 + now.tv_usec/1000;
    return 0;
}
#endif