Atrinik Server 2.5
server/time.c
Go to the documentation of this file.
00001 /************************************************************************
00002 *            Atrinik, a Multiplayer Online Role Playing Game            *
00003 *                                                                       *
00004 *    Copyright (C) 2009-2011 Alex Tokar and Atrinik Development Team    *
00005 *                                                                       *
00006 * Fork from Daimonin (Massive Multiplayer Online Role Playing Game)     *
00007 * and Crossfire (Multiplayer game for X-windows).                       *
00008 *                                                                       *
00009 * This program is free software; you can redistribute it and/or modify  *
00010 * it under the terms of the GNU General Public License as published by  *
00011 * the Free Software Foundation; either version 2 of the License, or     *
00012 * (at your option) any later version.                                   *
00013 *                                                                       *
00014 * This program is distributed in the hope that it will be useful,       *
00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00017 * GNU General Public License for more details.                          *
00018 *                                                                       *
00019 * You should have received a copy of the GNU General Public License     *
00020 * along with this program; if not, write to the Free Software           *
00021 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.             *
00022 *                                                                       *
00023 * The author can be reached at admin@atrinik.org                        *
00024 ************************************************************************/
00025 
00030 #include <global.h>
00031 
00032 long max_time = MAX_TIME;
00033 
00035 #define PBUFLEN 100
00036 
00038 static long process_utime_save[PBUFLEN];
00040 static long psaveind;
00042 static long process_max_utime = 0;
00044 static long process_min_utime = 999999999;
00045 static long process_tot_mtime;
00046 long pticks;
00047 static long process_utime_long_count;
00048 
00050 const char *season_name[SEASONS_PER_YEAR + 1] =
00051 {
00052     "The Season of New Year",
00053     "The Season of Growth",
00054     "The Season of Harvest",
00055     "The Season of Decay",
00056     "The Season of the Blizzard",
00057     "\n"
00058 };
00059 
00061 const char *weekdays[DAYS_PER_WEEK] =
00062 {
00063     "the Day of the Moon",
00064     "the Day of the Bull",
00065     "the Day of the Deception",
00066     "the Day of Thunder",
00067     "the Day of Freedom",
00068     "the Day of the Great Gods",
00069     "the Day of the Sun"
00070 };
00071 
00073 const char *month_name[MONTHS_PER_YEAR] =
00074 {
00075     "Month of the Ice Dragon",
00076     "Month of the Frost Giant",
00077     "Month of the Clouds",
00078     "Month of Gaea",
00079     "Month of the Harvest",
00080     "Month of Futility",
00081     "Month of the Dragon",
00082     "Month of the Sun",
00083     "Month of the Falling",
00084     "Month of the Dark Shades",
00085     "Month of the Great Infernus",
00086     "Month of the Ancient Darkness",
00087 };
00088 
00090 const char *periodsofday[PERIODS_PER_DAY] = {
00091     "Night",
00092     "Dawn",
00093     "Morning",
00094     "Noon",
00095     "Evening",
00096     "Dusk"
00097 };
00098 
00101 void reset_sleep()
00102 {
00103     int i;
00104 
00105     for (i = 0; i < PBUFLEN; i++)
00106     {
00107         process_utime_save[i] = 0;
00108     }
00109 
00110     psaveind = 0;
00111     process_max_utime = 0;
00112     process_min_utime = 999999999;
00113     process_tot_mtime = 0;
00114     pticks = 0;
00115 
00116     (void) GETTIMEOFDAY(&last_time);
00117 }
00118 
00121 static void log_time(long process_utime)
00122 {
00123     pticks++;
00124 
00125     if (++psaveind >= PBUFLEN)
00126     {
00127         psaveind = 0;
00128     }
00129 
00130     process_utime_save[psaveind] = process_utime;
00131 
00132     if (process_utime > process_max_utime)
00133     {
00134         process_max_utime = process_utime;
00135     }
00136 
00137     if (process_utime < process_min_utime)
00138     {
00139         process_min_utime = process_utime;
00140     }
00141 
00142     process_tot_mtime += process_utime / 1000;
00143 }
00144 
00149 void sleep_delta()
00150 {
00151     static struct timeval new_time;
00152     static struct timeval def_time = {0, 100000};
00153     static struct timeval sleep_time;
00154     long sleep_sec, sleep_usec;
00155 
00156     (void) GETTIMEOFDAY(&new_time);
00157 
00158     sleep_sec = last_time.tv_sec - new_time.tv_sec;
00159     sleep_usec = max_time - (new_time.tv_usec - last_time.tv_usec);
00160 
00161     /* This is very ugly, but probably the fastest for our use: */
00162     while (sleep_usec < 0)
00163     {
00164         sleep_usec += 1000000;
00165         sleep_sec -= 1;
00166     }
00167 
00168     while (sleep_usec > 1000000)
00169     {
00170         sleep_usec -= 1000000;
00171         sleep_sec += 1;
00172     }
00173 
00174     log_time((new_time.tv_sec - last_time.tv_sec) * 1000000 + new_time.tv_usec - last_time.tv_usec);
00175 
00176     if (sleep_sec >= 0 && sleep_usec > 0)
00177     {
00178         sleep_time.tv_sec = sleep_sec;
00179         sleep_time.tv_usec = sleep_usec;
00180 
00181         /*LOG(llevDebug, "SLEEP-Time: %ds and %dus\n", sleep_time.tv_sec, sleep_time.tv_usec);*/
00182         /* we ignore seconds to sleep - there is NO reason to put the server
00183          * for even a single second to sleep when there is someone connected. */
00184         if (sleep_time.tv_sec || sleep_time.tv_usec > 500000)
00185         {
00186             LOG(llevBug, "sleep_delta(): sleep delta out of range! (%"FMT64U"s %"FMT64U"us)\n", (uint64) sleep_time.tv_sec, (uint64) sleep_time.tv_usec);
00187         }
00188 
00189 #ifndef WIN32
00190         /* 'select' doesn't work on Windows, 'Sleep' is used instead */
00191         if (sleep_time.tv_sec || sleep_time.tv_usec > 500000)
00192         {
00193             select(0, NULL, NULL, NULL, &def_time);
00194         }
00195         else
00196         {
00197             select(0, NULL, NULL, NULL, &sleep_time);
00198         }
00199 #else
00200         if (sleep_time.tv_usec >= 1000)
00201         {
00202             Sleep((int) (sleep_time.tv_usec / 1000));
00203         }
00204         else if (sleep_time.tv_usec)
00205         {
00206             Sleep(1);
00207         }
00208 #endif
00209     }
00210     else
00211     {
00212         process_utime_long_count++;
00213     }
00214 
00215     /* Set last_time to when we're expected to wake up: */
00216     last_time.tv_usec += max_time;
00217 
00218     while (last_time.tv_usec > 1000000)
00219     {
00220         last_time.tv_usec -= 1000000;
00221         last_time.tv_sec++;
00222     }
00223 
00224     /* Don't do too much catching up:
00225      * (Things can still get jerky on a slow/loaded computer) */
00226     if (last_time.tv_sec * 1000000 + last_time.tv_usec < new_time.tv_sec * 1000000 + new_time.tv_usec)
00227     {
00228         last_time.tv_sec = new_time.tv_sec;
00229         last_time.tv_usec = new_time.tv_usec;
00230     }
00231 }
00232 
00237 void set_max_time(long t)
00238 {
00239     max_time = t;
00240 }
00241 
00245 void get_tod(timeofday_t *tod)
00246 {
00247     tod->year = todtick / HOURS_PER_YEAR;
00248     tod->month = (todtick / HOURS_PER_MONTH) % MONTHS_PER_YEAR;
00249     tod->day = (todtick % HOURS_PER_MONTH) / DAYS_PER_MONTH;
00250     tod->dayofweek = tod->day % DAYS_PER_WEEK;
00251     tod->hour = todtick % HOURS_PER_DAY;
00252     tod->minute = (pticks % PTICKS_PER_CLOCK) / (PTICKS_PER_CLOCK / 58);
00253 
00254     if (tod->minute > 59)
00255     {
00256         tod->minute = 59;
00257     }
00258 
00259     tod->weekofmonth = tod->day / WEEKS_PER_MONTH;
00260 
00261     if (tod->month < 3)
00262     {
00263         tod->season = 0;
00264     }
00265     else if (tod->month < 6)
00266     {
00267         tod->season = 1;
00268     }
00269     else if (tod->month < 9)
00270     {
00271         tod->season = 2;
00272     }
00273     else if (tod->month < 12)
00274     {
00275         tod->season = 3;
00276     }
00277     else
00278     {
00279         tod->season = 4;
00280     }
00281 
00282     /* Until 4:59 */
00283     if (tod->hour < 5)
00284     {
00285         tod->periodofday = 0;
00286     }
00287     else if (tod->hour < 8)
00288     {
00289         tod->periodofday = 1;
00290     }
00291     else if (tod->hour < 13)
00292     {
00293         tod->periodofday = 2;
00294     }
00295     else if (tod->hour < 15)
00296     {
00297         tod->periodofday = 3;
00298     }
00299     else if (tod->hour < 20)
00300     {
00301         tod->periodofday = 4;
00302     }
00303     else if (tod->hour < 23)
00304     {
00305         tod->periodofday = 5;
00306     }
00307     /* Back to night */
00308     else
00309     {
00310         tod->periodofday = 0;
00311     }
00312 }
00313 
00317 void print_tod(object *op)
00318 {
00319     timeofday_t tod;
00320     char *suf;
00321     int day;
00322 
00323     get_tod(&tod);
00324     new_draw_info_format(0, COLOR_WHITE, op, "It is %d minute%s past %d o'clock %s, on %s", tod.minute, ((tod.minute == 1) ? "" : "s"), ((tod.hour % (HOURS_PER_DAY / 2) == 0) ? (HOURS_PER_DAY / 2) : ((tod.hour) % (HOURS_PER_DAY / 2))), ((tod.hour >= (HOURS_PER_DAY / 2)) ? "pm" : "am"), weekdays[tod.dayofweek]);
00325 
00326     day = tod.day + 1;
00327 
00328     if (day == 1 || ((day % 10) == 1 && day > 20))
00329     {
00330         suf = "st";
00331     }
00332     else if (day == 2 || ((day % 10) == 2 && day > 20))
00333     {
00334         suf = "nd";
00335     }
00336     else if (day == 3 || ((day % 10) == 3 && day > 20))
00337     {
00338         suf = "rd";
00339     }
00340     else
00341     {
00342         suf = "th";
00343     }
00344 
00345     new_draw_info_format(0, COLOR_WHITE, op, "The %d%s Day of the %s, Year %d", day, suf, month_name[tod.month], tod.year + 1);
00346     new_draw_info_format(0, COLOR_WHITE, op, "Time of Year: %s", season_name[tod.season]);
00347 }
00348 
00352 void time_info(object *op)
00353 {
00354     int tot = 0, maxt = 0, mint = 99999999, long_count = 0, i;
00355 
00356     print_tod(op);
00357 
00358     if (!QUERY_FLAG(op, FLAG_WIZ))
00359     {
00360         return;
00361     }
00362 
00363     new_draw_info_format(0, COLOR_WHITE, op, "Total time:\nticks=%ld  time=%ld.%2ld", pticks, process_tot_mtime / 1000, process_tot_mtime % 1000);
00364     new_draw_info_format(0, COLOR_WHITE, op, "avg time=%ldms  max time=%ldms  min time=%ldms", process_tot_mtime / pticks, process_max_utime / 1000, process_min_utime / 1000);
00365     new_draw_info_format(0, COLOR_WHITE, op, "ticks longer than max time (%ldms) = %ld (%ld%%)", max_time / 1000, process_utime_long_count, 100 * process_utime_long_count / pticks);
00366     new_draw_info_format(0, COLOR_WHITE, op, "Time last %ld ticks:", pticks > PBUFLEN ? PBUFLEN : pticks);
00367 
00368     for (i = 0; i < (pticks > PBUFLEN ? PBUFLEN : pticks); i++)
00369     {
00370         tot += process_utime_save[i];
00371 
00372         if (process_utime_save[i] > maxt)
00373         {
00374             maxt = process_utime_save[i];
00375         }
00376 
00377         if (process_utime_save[i] < mint)
00378         {
00379             mint = process_utime_save[i];
00380         }
00381 
00382         if (process_utime_save[i] > max_time)
00383         {
00384             long_count++;
00385         }
00386     }
00387 
00388     new_draw_info_format(0, COLOR_WHITE, op, "avg time=%ldms  max time=%dms  min time=%dms", tot / (pticks > PBUFLEN ? PBUFLEN : pticks) / 1000, maxt / 1000, mint / 1000);
00389     new_draw_info_format(0, COLOR_WHITE, op, "ticks longer than max time (%ldms) = %d (%ld%%)", max_time / 1000, long_count, 100 * long_count / (pticks > PBUFLEN ? PBUFLEN : pticks));
00390 }
00391 
00395 long seconds()
00396 {
00397     struct timeval now;
00398 
00399     (void) GETTIMEOFDAY(&now);
00400     return now.tv_sec;
00401 }