Προς το περιεχόμενο

Προτεινόμενες αναρτήσεις

Δημοσ.

Καλησπέρα σε όλους,

 

Θα ήθελα να ρωτήσω με ποιο τρόπο μπορεί κανείς να φτιάξει μία αξιόπιστη συνάρτηση καθυστέρησης. Προσπαθώ εδώ και καιρό να φτιάξω μια γεννήτρια πακέτων και δεν μου κάθετε με τίποτα! Οι συναρτήσεις της "times.h" sleep(), usleep() και nanosleep() αφανώς είναι πολύ αργές και αφετέρου η nanosleep μάλλον δεν δουλεύει σωστά καθότι και μηδενικό όρισμα μου προκαλεί αισθητά μεγάλη καθυστέρηση.

 

Κατέληξα να χρησιμοποιώ μία for loop αλλά αυτή είναι απευθείας εξαρτώμενη με το φόρτο του συστήματος και την προτεραιότητα του thread και λιγότερο εξαρτώμενη από τον αριθμό των επαναλήψεων.

 

Έχει κανείς καμιά ιδέα που να είναι robust και thread safe? Απορώ πως μπορούν και διατηρούν χρονισμούς σε πακέτα όπως π.χ. Ostinato κτλπ....

Δημοσ.

Καταρχήν θα πρέπει να πεις πώς ορίζεις το "αξιόπιστη". Θα πρέπει επίσης να πεις τι απαιτήσεις έχεις πέραν της αξιοπιστίας.

 

Γενικά μιλώντας τα πράγματα που μπορείς να κάνεις είναι δύο, που τα έχεις αναφέρει:

  1. Μπαίνεις σε busy loop και μετράς συνεχώς πόσος χρόνος έχει περάσει.
  2. Ζητάς από το λειτουργικό να σου μπλοκάρει το thread για χρονικό διάστημα X.

Για προφανείς λόγους δεν είναι δυνατόν να έχεις άπειρη ακρίβεια με κανέναν από τους 2 παραπάνω μηχανισμούς, αν εισαι σε busy loop τότε εξαρτάσαι από το thread scheduling του λειτουργικού και αν ζητήσεις μπλοκάρισμα τότε απ' όσο ξέρω δε μπορείς να έχεις καλύτερη ακρίβεια από όσο είναι το thread timeslice quantum (αλλά ίσως και να υπάρχει τρόπος, δεν είμαι ειδικός στο θέμα). Σε κάθε περίπτωση για καλά αποτελέσματα θα χρειαστεί να καταφύγεις σε συγκεκριμένες συναρτήσεις που προσφέρει το λειτουργικό (άρα αυτομάτως ξεχνάς time.h και οτιδήποτε άλλο cross-platform).

 

Αλλά μήπως υπάρχει καλύτερη λύση γι' αυτό που θες να καταφέρεις ("γεννήτρια πακέτων?")

Δημοσ.

Καταρχάς ευχαριστώ για την απάντηση, το αξιόπιστη είναι σχετικό, όσο αξιόπιστη γεννήτρια μπορεί να γίνει ένα pc, απλά με ενδιαφέρει όταν βάζω σε μια συνάρτηση μία τιμή πχ 1000 μονάδες delay το αποτέλεσμα να είναι πάντα πιο αργό από μία τιμή πχ 500. Το cross-platform δεν με ενδιαφέρει δουλεύω με Linuxaki και POSIX πιο συγκεκριμένα.

 

Το όλο σκηνικό περιλαμβάνει 2 συστήματα (pc) συνδεμένα μεταξύ τους. Το ένα έχει τον ρόλο του στόχου/σερβερ, δηλαδή μαζεύει κίνηση από το δίκτυο κάνει κάποιο packet manipulation και τα ξαναρίχνει πάλι πίσω. Ε αυτό το πράγμα πρέπει να οριοθετηθεί/βαθμονομηθεί για το που δουλεύει και πού όχι. Γιαυτό μπήκα στο τρυπάκι και έγραψα μία "γεννήτρια" με πρακτικά 2 νήματα. Το ένα στέλνει και το άλλο μαζεύει. Αυτό που στέλνει πρέπει να προσαρμόζει τον ρυθμό που στέλνει πακέτα γιατί άμα το κάνω με το χέρι δεν θα τελειώσω ποτέ! Το θέμα με το loop που είπα  και πριν είναι ότι όταν ζοριστεί το μηχάνημα τα φτύνει με αποτέλεσμα να υπάρχουν περιπτώσεις που για εντελώς διαφορετικές τιμές καθυστέρησης να παίρνω διαφορετικά αποτελέσματα....

 

Γενικότερα αυτό είναι το κομμάτι του κώδικα που χρησιμοποιώ για το νήμα που στέλνει και την εισαγωγή καθυστέρησης. Όπως βλέπεις έχω δοκιμάσει αρκετά πράγματα (γενικά έιναι χάλια ο κώδικας :-D ) χωρίς αποτέλεσμα.... Όσον αφορά το thread scheduling, θα του ψάξω και θα σου πώ.

memcpy(inthread,arg,sizeof(ThreadArg));
	struct timeval t0,t1;
	struct timespec del={0};
	int tr_sock=((ThreadArg*)inthread)->sock;
	void *tr_buffer=((ThreadArg*)inthread)->buffer;
	int size=((ThreadArg*)inthread)->size;
	long int delay=((ThreadArg*)inthread)->delay;
	int tr_loop=((ThreadArg*)inthread)->loop;
	del.tv_sec=0;
	del.tv_nsec=delay*1000L;
	//printf("Socket ID: %1i.\n",tr_sock);
	//pthread_mutex_lock(&mymutex);
	gettimeofday(&t0, 0); //time measure
	printf("test1\n");
	sent=0;
	while(sent!=PACKETS){
		sendto(tr_sock,tr_buffer,size+ETH_HEADER_LEN,0,(struct sockaddr*)&socket_address,sizeof(socket_address)); //send packtes
		sent++;
		//pthread_mutex_lock(&mymutex);
		//ddelay(delay);
		//nanosleep(&del,(struct timespec*)NULL);
		//pthread_mutex_unlock(&mymutex);
	}
	gettimeofday(&t1, 0);
	//pthread_mutex_unlock(&mymutex);
	//pthread_mutex_unlock(&inthreadmutex);
	//pthread_cancel(threadID2);
	elapsed = ((t1.tv_sec-t0.tv_sec)*1000000 + (t1.tv_usec-t0.tv_usec));
	result(tr_sock,tr_loop,delay,size,elapsed);
	printf("Transmitter Thread Exiting...\n");
	usleep(1);
	control=0;
	free(inthread);
        ......

 

 

void ddelay(long int cycles){
	float k,a;
	long int loop,i;
	loop=abs(cycles);
	k=99990;
	for(i=0;i<=loop;i++){
		a=k/3;a=0;
	}

 

 

 

"Αλλά μήπως υπάρχει καλύτερη λύση γι' αυτό που θες να καταφέρεις ("γεννήτρια πακέτων?")"

 

Ξέρεις κάποιο άλλο τρόπο αποστολής πακέτων που να μπορεί να γίνετε από μόνος του adjust;

Δημοσ.

Δοκίμασε την clock_nanosleep() με απόλυτο χρόνο ως όρισμα, γιατί η nanosleep() χρησιμοποιεί σχετικό χρόνο με αποτέλεσμα να επιμηκύνεται η καθυστέρηση σε περίπτωση που την διακόπτουν συνεχώς άλλα signals (συνεχίζει από εκεί που είχε μείνει πριν από κάθε διακοπή).

Δημοσ.

Δοκίμασε την clock_nanosleep() με απόλυτο χρόνο ως όρισμα, γιατί η nanosleep() χρησιμοποιεί σχετικό χρόνο με αποτέλεσμα να επιμηκύνεται η καθυστέρηση σε περίπτωση που την διακόπτουν συνεχώς άλλα signals (συνεχίζει από εκεί που είχε μείνει πριν από κάθε διακοπή).

 

 

Όπως είπε και ο migf1 η nanosleep θέλει λίγο μασαζ για να δουλέψει. Δες εδώ μια υλοποίηση σχεδόν copy paste από SDL:

 

http://code.google.com/p/anki-3d-engine/source/browse/trunk/src/util/HighRezTimerPosix.cpp

 

Συγκεκριμένα δες την HighRezTimer::sleep

 

Ευχαριστώ για το ενδιαφέρων, τελικά ούτε η clock_nanosleep() δούλεψε, τι να πω, μάλλον δεν κάνω κάτι καλά εγώ. Όπως και να έχει βρήκα και άλλη μία λύση που μάλλον θα πρέπει να την γράψω σε C++.  Την παραθέτω (είναι από τον source κώδικα του Ostinato packet genenrator) :

  1. https://code.google.com/p/ostinato/
    
    void PcapPort::PortTransmitter::udelay(long usec)
    {
    #if defined(Q_OS_WIN32)
        LARGE_INTEGER tgtTicks;
        LARGE_INTEGER curTicks;
    
        QueryPerformanceCounter(&curTicks);
        tgtTicks.QuadPart = curTicks.QuadPart + (usec*ticksFreq_)/1000000;
    
        while (curTicks.QuadPart < tgtTicks.QuadPart)
            QueryPerformanceCounter(&curTicks);
    #elif defined(Q_OS_LINUX)
        struct timeval delay, target, now;
    
        //qDebug("usec delay = %ld", usec);
    
        delay.tv_sec = 0;
        delay.tv_usec = usec;
    
        while (delay.tv_usec >= 1000000)
        {
            delay.tv_sec++;
            delay.tv_usec -= 1000000;
        }
    
        gettimeofday(&now, NULL);
        timeradd(&now, &delay, &target);
    
        do {
            gettimeofday(&now, NULL);
        } while (timercmp(&now, &target, <));
    #else
        QThread::usleep(usec);
    #endif 
    }
    
    

 

while (timercmp(&now, &target, <)); //σε αυτή την γραμμή μου χτυπάει σφάλμα (στον τελεστή "<") στον gcc ... -lrt

Δημοσ.

Όπως είπε και ο migf1 η nanosleep θέλει λίγο μασαζ για να δουλέψει. Δες εδώ μια υλοποίηση σχεδόν copy paste από SDL:

 

http://code.google.com/p/anki-3d-engine/source/browse/trunk/src/util/HighRezTimerPosix.cpp

 

Συγκεκριμένα δες την HighRezTimer::sleep

 

Από ότι βλέπω, ελλείψει της nanosleep() χρησιμοποιεί την select() (που μου κάνει εντύπωση γιατί έχει ακρίβεια microsecs) και διαχειρίζεται χειροκίνητα το διάστημα που απομένει σε περίπτωση interrupt. Νομίζω πως η clock_nanosleep() τον γλιτώνει από την έξτρα βαβούρα, αλλά έχει περάσει καιρός από τότε που είχα ασχοληθεί και ενδέχεται να κάνω και λάθος... πιθανότατα να το κάνει για λόγους συμβατότητας όμως, η select() είναι πολύ πιο portable.

 

Παρεμπιπτόντως, θα μπορούσε να χρησιμοποιήσει την pselect() αντί της select() η οποία έχει ακρίβεια nanosecs νομίζω (διασταυρώστε το όμως, γιατί ίσως θυμάμαι λάθος) αλλά έτσι θα έχανε τη δυνατότητα να διαχειριστεί το διάστημα που απομένει σε περίπτωση interrupt.

 

Ευχαριστώ για το ενδιαφέρων, τελικά ούτε η clock_nanosleep() δούλεψε, τι να πω, μάλλον δεν κάνω κάτι καλά εγώ. Όπως και να έχει βρήκα και άλλη μία λύση που μάλλον θα πρέπει να την γράψω σε C++.  Την παραθέτω (είναι από τον source κώδικα του Ostinato packet genenrator) :

 

 

  •  
  • https://code.google.com/p/ostinato/
    
    void PcapPort::PortTransmitter::udelay(long usec)
    {
    #if defined(Q_OS_WIN32)
        LARGE_INTEGER tgtTicks;
        LARGE_INTEGER curTicks;
    
        QueryPerformanceCounter(&curTicks);
        tgtTicks.QuadPart = curTicks.QuadPart + (usec*ticksFreq_)/1000000;
    
        while (curTicks.QuadPart < tgtTicks.QuadPart)
            QueryPerformanceCounter(&curTicks);
    #elif defined(Q_OS_LINUX)
        struct timeval delay, target, now;
    
        //qDebug("usec delay = %ld", usec);
    
        delay.tv_sec = 0;
        delay.tv_usec = usec;
    
        while (delay.tv_usec >= 1000000)
        {
            delay.tv_sec++;
            delay.tv_usec -= 1000000;
        }
    
        gettimeofday(&now, NULL);
        timeradd(&now, &delay, &target);
    
        do {
            gettimeofday(&now, NULL);
        } while (timercmp(&now, &target, <));
    #else
        QThread::usleep(usec);
    #endif 
    }
    
    

 

while (timercmp(&now, &target, <)); //σε αυτή την γραμμή μου χτυπάει σφάλμα (στον τελεστή "<") στον gcc ... -lrt

 

Ti error σου βγάζει;

 

Δεν είμαι εξοικειωμένος με τις timerXXX() βλέπω όμως στην τεκμηρίωση του Linux ότι είναι BSD_UNIX specific. Οπότε δοκίμασε στον gcc -D_BSD_SOURCE (το οποίο όμως μπορεί να σου περάσει αυτές και να χτυπήσει αλλού).

 

Βλέπω επίσης πως κι αυτές με microsecs ασχολούνται αντί για nanosecs.

Δημοσ.

while (timercmp(&now, &target, <)); //σε αυτή την γραμμή μου χτυπάει σφάλμα (στον τελεστή "<") στον gcc ... -lrt

Ti error σου βγάζει;

 

Δεν είμαι εξοικειωμένος με τις timerXXX() βλέπω όμως στην τεκμηρίωση του Linux ότι είναι BSD_UNIX specific. Οπότε δοκίμασε στον gcc -D_BSD_SOURCE (το οποίο όμως μπορεί να σου περάσει αυτές και να χτυπήσει αλλού).

 

Βλέπω επίσης πως κι αυτές με microsecs ασχολούνται αντί για nanosecs.

Κανονικά θα έπρεπε να παίζει και χωρίς να ορίσεις κάποιο macro.
#include <stdio.h>
#include <sys/time.h>

int main(void)
{
    struct timeval delay, target, now;

    delay.tv_sec = 0;
    delay.tv_usec = 3250000;

    while (delay.tv_usec >= 1000000)
    {
        delay.tv_sec++;
        delay.tv_usec -= 1000000;
    }

    gettimeofday(&now, NULL);
    timeradd(&now, &delay, &target);
    printf("orig sec = %d - usec = %d\n", now.tv_sec, now.tv_usec);

    do {
        gettimeofday(&now, NULL);
    } while (timercmp(&now, &target, <));
    printf("new  sec = %d - usec = %d\n", now.tv_sec, now.tv_usec);

    return 0;
}

Έξοδος:
orig sec = 1364931292 - usec = 246991
new  sec = 1364931295 - usec = 496991
** Τα printf είναι λάθoς. Τα έβαλα καταχρηστικά για να δούμε ότι έπαιξε για 3.250sec **
Δημοσ.

Με μονάδα χρόνου το 1usec είμαι καλυμμένος πιστεύω απλά δεν δουλεύει η usleep();

 

#include <sys/times.h>
#include <time.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
/* Display 'msg' and process times */
void *displayProcessTimes(){
        struct timeval delay;
        struct timeval target;
        struct timeval now;
        delay.tv_sec = 0;
            delay.tv_usec = 1000;

            while (delay.tv_usec >= 1000000)
            {
                delay.tv_sec++;
                delay.tv_usec -= 1000000;
            }

            gettimeofday(&now, NULL);
            timeradd(&now, &delay, &target);

            do {
                gettimeofday(&now, NULL);
            } while (timercmp(&now, &target,<)); <--- Edw...

        pthread_exit(NULL);
}
pthread_t threadID1;
pthread_attr_t attr;
pthread_mutexattr_t mtx;

int main(int argc, char *argv[])
{
        void* statusID1;
        int *argID1;
        pthread_mutexattr_init(&mtx);
        pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_JOINABLE);

                pthread_create(&threadID1,&attr,displayProcessTimes,argID1);
                pthread_join(threadID1,&statusID1);
        return 0;
}

 

@imitheos απορώ που σου τρέχει.... λές να φταίει τίποτα άλλο;

Δημοσ.

Κανονικά θα έπρεπε να παίζει και χωρίς να ορίσεις κάποιο macro.

#include <sys/time.h>            <-----------------

 

 

 

 

#include <sys/times.h>           <-----------------
 

@imitheos απορώ που σου τρέχει.... λές να φταίει τίποτα άλλο;

 

 

Μήπως το times δεν φορτώνει τις σωστές δηλώσεις ?
Δημοσ.

...

@imitheos απορώ που σου τρέχει.... λές να φταίει τίποτα άλλο;

 

Μήπως τον χαλάνε τα real-time extension libs? Δοκίμασε χωρίς -lrt (αυτό ήταν για την clock_nanosleep() ).

Δημοσ.

Μήπως το times δεν φορτώνει τις σωστές δηλώσεις ?

 

Μήπως τον χαλάνε τα real-time extension libs? Δοκίμασε χωρίς -lrt (αυτό ήταν για την clock_nanosleep() ).

Αυτό με το times πρέπει να είναι λογικά μια και η manpage αναφέρει αντίστοιχα:

NAME

sys/times.h - file access and modification times structure

SYNOPSIS

#include <sys/times.h>

DESCRIPTION

The <sys/times.h> header shall define the structure tms, which is

returned by times() and includes at least the following members:

clock_t tms_utime User CPU time.

clock_t tms_stime System CPU time.

blah blah

NAME

sys/time.h - time types

SYNOPSIS

#include <sys/time.h>

DESCRIPTION

The <sys/time.h> header shall define the timeval structure that

includes at least the following members:

time_t tv_sec Seconds.

suseconds_t tv_usec Microseconds.

blah blah

Το times.h είναι για άλλη δουλειά.

 

* Για νανο-δευτερόλεπτα (τουλάχιστον σε linux και netbsd) υπάρχει η timespec αντί για την timeval *

Δημοσ.
gcc  delayintroduce.c -o delaytime -lpthread (χωρίς macro και με macro  τα ίδια....)

 .

 .

 .

delayintroduce.c:34:38: error: expected expression before ‘<’ token

 

 

Θα το κοιτάξω και αύριο αλλά απορώ.... Θα το ψάξω και για C++ (did not see that comming!) και θα κοιτάξω μην χρησιμοποιήσω την pcap.h βιβλιοθήκη μπας και κάνω πιο γρήγορα! γιατί με έχει πάει αρκετά πίσω αυτό!

 

Ευχαριστώ για την βοήθεια άμα έχει κανείς καμία άλλη ιδέα ευπρόσδεκτη!

Δημοσ.

Και με macro? Επίσης, διόρθωσες τον header που σου υπέδειξε ο ημίθεος;
 
ΥΓ. Ποια έκδοση του gcc χρησιμοποιείς και σε ποιο λειτουργικό; Αν δεν δουλέψει τίποτα από τα παραπάνω, δοκίμασε να δεις την τεκμηρίωση των συναρτήσεων στην glibc που χρησιμοποιείς... η latest είναι εδώ: http://www.gnu.org/software/libc/manual/
 
EDIT:
 
Βασικά αν είσαι σε Unix/Linux, δεν χρειάζεται να κατεβάσεις την τεκμηρίωση... γράψε απευθείας: man function_name στο shell.


EDIT2:

 

...
Θα το κοιτάξω και αύριο αλλά απορώ.... Θα το ψάξω και για C++ (did not see that comming!)

 

Δεν νομίζω ρε συ ότι ο sleeper είναι λόγος να αλλάξεις γλώσσα! Μάλλον κάτι δεν κάνεις καλά.

 

και θα κοιτάξω μην χρησιμοποιήσω την pcap.h βιβλιοθήκη μπας και κάνω πιο γρήγορα! γιατί με έχει πάει αρκετά πίσω αυτό!
...

 

Γιατί σε έχει πάει πίσω; Ίσα-ίσα που σου ανοίγει τον δρόμο για να κάνεις το πρόγραμμά σου portable και για Windows (μέσω της WinPcap) με το minimum possible effort.

Δημοσ.

Τελικά η κούραση χτες με είχε τυφλώσει! To header έφταιγε όπως έλεγε  ο imitheos (thanks!!!) ιδού τα αποτελέσματα:

 

 

real 0m1.137s
user 0m0.988s
sys 0m0.052s
 
real 0m1.044s
user 0m1.000s
sys 0m0.036s
 
είναι για 1000 επαναλήψεις (pthread create/join με το σχετικό overhead) των 1000us... θεωρώ ότι είμαι κοντά.
 

 

Γιατί σε έχει πάει πίσω; Ίσα-ίσα που σου ανοίγει τον δρόμο για να κάνεις το πρόγραμμά σου portable και για Windows (μέσω της WinPcap) με το minimum possible effort.

 

Πήγε πίσω το project καμιά βδομάδα ++ ψάχνοντας λύση στο delay( βάλε καρναβάλια και 25 Μαρτίου τα λέγαμε!) . To pcap δεν το χρησιμοποιώ γιατί μου φάνηκε πιο εύκολο να σηκώσω δύο threads και  με ένα mac socket στο καθένα και να στέλνω από την μία και να τσεκάρω στην άλλη για πακέτο.. Θα δείξει.... το portability δεν είναι το κύριο μέλημα μου αυτή την στιγμή. Σίγουρα το pcap είναι μια καλή λύση και από ότι έχω δει το χρησιμοποιούν όλα τα cross platform προγράμματα όπως wireshark/ostinato κτλπ απλά δεν το σκέφτηκα γιατί και στο άλλο σύστημα που είναι και το κύριο μου είχα πάρει την απόφαση να μην το χρησιμοποιήσω.

Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε

Πρέπει να είστε μέλος για να αφήσετε σχόλιο

Δημιουργία λογαριασμού

Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!

Δημιουργία νέου λογαριασμού

Σύνδεση

Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.

Συνδεθείτε τώρα
  • Δημιουργία νέου...