cyberrobot Δημοσ. 1 Απριλίου 2013 Δημοσ. 1 Απριλίου 2013 Καλησπέρα σε όλους, Θα ήθελα να ρωτήσω με ποιο τρόπο μπορεί κανείς να φτιάξει μία αξιόπιστη συνάρτηση καθυστέρησης. Προσπαθώ εδώ και καιρό να φτιάξω μια γεννήτρια πακέτων και δεν μου κάθετε με τίποτα! Οι συναρτήσεις της "times.h" sleep(), usleep() και nanosleep() αφανώς είναι πολύ αργές και αφετέρου η nanosleep μάλλον δεν δουλεύει σωστά καθότι και μηδενικό όρισμα μου προκαλεί αισθητά μεγάλη καθυστέρηση. Κατέληξα να χρησιμοποιώ μία for loop αλλά αυτή είναι απευθείας εξαρτώμενη με το φόρτο του συστήματος και την προτεραιότητα του thread και λιγότερο εξαρτώμενη από τον αριθμό των επαναλήψεων. Έχει κανείς καμιά ιδέα που να είναι robust και thread safe? Απορώ πως μπορούν και διατηρούν χρονισμούς σε πακέτα όπως π.χ. Ostinato κτλπ....
defacer Δημοσ. 1 Απριλίου 2013 Δημοσ. 1 Απριλίου 2013 Καταρχήν θα πρέπει να πεις πώς ορίζεις το "αξιόπιστη". Θα πρέπει επίσης να πεις τι απαιτήσεις έχεις πέραν της αξιοπιστίας. Γενικά μιλώντας τα πράγματα που μπορείς να κάνεις είναι δύο, που τα έχεις αναφέρει: Μπαίνεις σε busy loop και μετράς συνεχώς πόσος χρόνος έχει περάσει. Ζητάς από το λειτουργικό να σου μπλοκάρει το thread για χρονικό διάστημα X. Για προφανείς λόγους δεν είναι δυνατόν να έχεις άπειρη ακρίβεια με κανέναν από τους 2 παραπάνω μηχανισμούς, αν εισαι σε busy loop τότε εξαρτάσαι από το thread scheduling του λειτουργικού και αν ζητήσεις μπλοκάρισμα τότε απ' όσο ξέρω δε μπορείς να έχεις καλύτερη ακρίβεια από όσο είναι το thread timeslice quantum (αλλά ίσως και να υπάρχει τρόπος, δεν είμαι ειδικός στο θέμα). Σε κάθε περίπτωση για καλά αποτελέσματα θα χρειαστεί να καταφύγεις σε συγκεκριμένες συναρτήσεις που προσφέρει το λειτουργικό (άρα αυτομάτως ξεχνάς time.h και οτιδήποτε άλλο cross-platform). Αλλά μήπως υπάρχει καλύτερη λύση γι' αυτό που θες να καταφέρεις ("γεννήτρια πακέτων?")
cyberrobot Δημοσ. 1 Απριλίου 2013 Μέλος Δημοσ. 1 Απριλίου 2013 Καταρχάς ευχαριστώ για την απάντηση, το αξιόπιστη είναι σχετικό, όσο αξιόπιστη γεννήτρια μπορεί να γίνει ένα pc, απλά με ενδιαφέρει όταν βάζω σε μια συνάρτηση μία τιμή πχ 1000 μονάδες delay το αποτέλεσμα να είναι πάντα πιο αργό από μία τιμή πχ 500. Το cross-platform δεν με ενδιαφέρει δουλεύω με Linuxaki και POSIX πιο συγκεκριμένα. Το όλο σκηνικό περιλαμβάνει 2 συστήματα (pc) συνδεμένα μεταξύ τους. Το ένα έχει τον ρόλο του στόχου/σερβερ, δηλαδή μαζεύει κίνηση από το δίκτυο κάνει κάποιο packet manipulation και τα ξαναρίχνει πάλι πίσω. Ε αυτό το πράγμα πρέπει να οριοθετηθεί/βαθμονομηθεί για το που δουλεύει και πού όχι. Γιαυτό μπήκα στο τρυπάκι και έγραψα μία "γεννήτρια" με πρακτικά 2 νήματα. Το ένα στέλνει και το άλλο μαζεύει. Αυτό που στέλνει πρέπει να προσαρμόζει τον ρυθμό που στέλνει πακέτα γιατί άμα το κάνω με το χέρι δεν θα τελειώσω ποτέ! Το θέμα με το loop που είπα και πριν είναι ότι όταν ζοριστεί το μηχάνημα τα φτύνει με αποτέλεσμα να υπάρχουν περιπτώσεις που για εντελώς διαφορετικές τιμές καθυστέρησης να παίρνω διαφορετικά αποτελέσματα.... Γενικότερα αυτό είναι το κομμάτι του κώδικα που χρησιμοποιώ για το νήμα που στέλνει και την εισαγωγή καθυστέρησης. Όπως βλέπεις έχω δοκιμάσει αρκετά πράγματα (γενικά έιναι χάλια ο κώδικας ) χωρίς αποτέλεσμα.... Όσον αφορά το 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;
migf1 Δημοσ. 2 Απριλίου 2013 Δημοσ. 2 Απριλίου 2013 Δοκίμασε την clock_nanosleep() με απόλυτο χρόνο ως όρισμα, γιατί η nanosleep() χρησιμοποιεί σχετικό χρόνο με αποτέλεσμα να επιμηκύνεται η καθυστέρηση σε περίπτωση που την διακόπτουν συνεχώς άλλα signals (συνεχίζει από εκεί που είχε μείνει πριν από κάθε διακοπή).
godlike Δημοσ. 2 Απριλίου 2013 Δημοσ. 2 Απριλίου 2013 Όπως είπε και ο migf1 η nanosleep θέλει λίγο μασαζ για να δουλέψει. Δες εδώ μια υλοποίηση σχεδόν copy paste από SDL: http://code.google.com/p/anki-3d-engine/source/browse/trunk/src/util/HighRezTimerPosix.cpp Συγκεκριμένα δες την HighRezTimer::sleep
cyberrobot Δημοσ. 2 Απριλίου 2013 Μέλος Δημοσ. 2 Απριλίου 2013 Δοκίμασε την 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) : 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 Δημοσ. 2 Απριλίου 2013 Δημοσ. 2 Απριλίου 2013 Όπως είπε και ο 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.
imitheos Δημοσ. 2 Απριλίου 2013 Δημοσ. 2 Απριλίου 2013 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 **
cyberrobot Δημοσ. 2 Απριλίου 2013 Μέλος Δημοσ. 2 Απριλίου 2013 Με μονάδα χρόνου το 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 απορώ που σου τρέχει.... λές να φταίει τίποτα άλλο;
imitheos Δημοσ. 2 Απριλίου 2013 Δημοσ. 2 Απριλίου 2013 Κανονικά θα έπρεπε να παίζει και χωρίς να ορίσεις κάποιο macro. #include <sys/time.h> <----------------- #include <sys/times.h> <----------------- @imitheos απορώ που σου τρέχει.... λές να φταίει τίποτα άλλο; Μήπως το times δεν φορτώνει τις σωστές δηλώσεις ?
migf1 Δημοσ. 2 Απριλίου 2013 Δημοσ. 2 Απριλίου 2013 ... @imitheos απορώ που σου τρέχει.... λές να φταίει τίποτα άλλο; Μήπως τον χαλάνε τα real-time extension libs? Δοκίμασε χωρίς -lrt (αυτό ήταν για την clock_nanosleep() ).
imitheos Δημοσ. 2 Απριλίου 2013 Δημοσ. 2 Απριλίου 2013 Μήπως το 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 *
cyberrobot Δημοσ. 2 Απριλίου 2013 Μέλος Δημοσ. 2 Απριλίου 2013 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 βιβλιοθήκη μπας και κάνω πιο γρήγορα! γιατί με έχει πάει αρκετά πίσω αυτό! Ευχαριστώ για την βοήθεια άμα έχει κανείς καμία άλλη ιδέα ευπρόσδεκτη!
migf1 Δημοσ. 2 Απριλίου 2013 Δημοσ. 2 Απριλίου 2013 Και με 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.
cyberrobot Δημοσ. 3 Απριλίου 2013 Μέλος Δημοσ. 3 Απριλίου 2013 Τελικά η κούραση χτες με είχε τυφλώσει! 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 κτλπ απλά δεν το σκέφτηκα γιατί και στο άλλο σύστημα που είναι και το κύριο μου είχα πάρει την απόφαση να μην το χρησιμοποιήσω.
Προτεινόμενες αναρτήσεις
Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε
Πρέπει να είστε μέλος για να αφήσετε σχόλιο
Δημιουργία λογαριασμού
Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!
Δημιουργία νέου λογαριασμούΣύνδεση
Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.
Συνδεθείτε τώρα