timevar.c revision 132718
190075Sobrien/* Timing variables for measuring compiler performance. 2132718Skan Copyright (C) 2000, 2003 Free Software Foundation, Inc. 390075Sobrien Contributed by Alex Samuel <samuel@codesourcery.com> 490075Sobrien 590075SobrienThis file is part of GCC. 690075Sobrien 790075SobrienGCC is free software; you can redistribute it and/or modify it under 890075Sobrienthe terms of the GNU General Public License as published by the Free 990075SobrienSoftware Foundation; either version 2, or (at your option) any later 1090075Sobrienversion. 1190075Sobrien 1290075SobrienGCC is distributed in the hope that it will be useful, but WITHOUT ANY 1390075SobrienWARRANTY; without even the implied warranty of MERCHANTABILITY or 1490075SobrienFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1590075Sobrienfor more details. 1690075Sobrien 1790075SobrienYou should have received a copy of the GNU General Public License 1890075Sobrienalong with GCC; see the file COPYING. If not, write to the Free 1990075SobrienSoftware Foundation, 59 Temple Place - Suite 330, Boston, MA 2090075Sobrien02111-1307, USA. */ 2190075Sobrien 2290075Sobrien#include "config.h" 2390075Sobrien#include "system.h" 2490075Sobrien#ifdef HAVE_SYS_TIMES_H 2590075Sobrien# include <sys/times.h> 2690075Sobrien#endif 2790075Sobrien#ifdef HAVE_SYS_RESOURCE_H 2890075Sobrien#include <sys/resource.h> 2990075Sobrien#endif 30132718Skan#include "coretypes.h" 31132718Skan#include "tm.h" 32132718Skan#include "intl.h" 33132718Skan#include "rtl.h" 34132718Skan#include "toplev.h" 3590075Sobrien 3690075Sobrien#ifndef HAVE_CLOCK_T 3790075Sobrientypedef int clock_t; 3890075Sobrien#endif 3990075Sobrien 4090075Sobrien#ifndef HAVE_STRUCT_TMS 4190075Sobrienstruct tms 4290075Sobrien{ 4390075Sobrien clock_t tms_utime; 4490075Sobrien clock_t tms_stime; 4590075Sobrien clock_t tms_cutime; 4690075Sobrien clock_t tms_cstime; 4790075Sobrien}; 4890075Sobrien#endif 4990075Sobrien 5090075Sobrien#ifndef RUSAGE_SELF 5190075Sobrien# define RUSAGE_SELF 0 5290075Sobrien#endif 5390075Sobrien 5490075Sobrien/* Calculation of scale factor to convert ticks to microseconds. 5590075Sobrien We mustn't use CLOCKS_PER_SEC except with clock(). */ 5690075Sobrien#if HAVE_SYSCONF && defined _SC_CLK_TCK 5790075Sobrien# define TICKS_PER_SECOND sysconf (_SC_CLK_TCK) /* POSIX 1003.1-1996 */ 5890075Sobrien#else 5990075Sobrien# ifdef CLK_TCK 6090075Sobrien# define TICKS_PER_SECOND CLK_TCK /* POSIX 1003.1-1988; obsolescent */ 6190075Sobrien# else 6290075Sobrien# ifdef HZ 6390075Sobrien# define TICKS_PER_SECOND HZ /* traditional UNIX */ 6490075Sobrien# else 6590075Sobrien# define TICKS_PER_SECOND 100 /* often the correct value */ 6690075Sobrien# endif 6790075Sobrien# endif 6890075Sobrien#endif 6990075Sobrien 7090075Sobrien/* Prefer times to getrusage to clock (each gives successively less 7190075Sobrien information). */ 7290075Sobrien#ifdef HAVE_TIMES 73132718Skan# if defined HAVE_DECL_TIMES && !HAVE_DECL_TIMES 74132718Skan extern clock_t times (struct tms *); 75132718Skan# endif 7690075Sobrien# define USE_TIMES 7790075Sobrien# define HAVE_USER_TIME 7890075Sobrien# define HAVE_SYS_TIME 7990075Sobrien# define HAVE_WALL_TIME 8090075Sobrien#else 8190075Sobrien#ifdef HAVE_GETRUSAGE 82132718Skan# if defined HAVE_DECL_GETRUSAGE && !HAVE_DECL_GETRUSAGE 83132718Skan extern int getrusage (int, struct rusage *); 84132718Skan# endif 8590075Sobrien# define USE_GETRUSAGE 8690075Sobrien# define HAVE_USER_TIME 8790075Sobrien# define HAVE_SYS_TIME 8890075Sobrien#else 8990075Sobrien#ifdef HAVE_CLOCK 90132718Skan# if defined HAVE_DECL_CLOCK && !HAVE_DECL_CLOCK 91132718Skan extern clock_t clock (void); 92132718Skan# endif 9390075Sobrien# define USE_CLOCK 9490075Sobrien# define HAVE_USER_TIME 9590075Sobrien#endif 9690075Sobrien#endif 9790075Sobrien#endif 9890075Sobrien 9990075Sobrien/* libc is very likely to have snuck a call to sysconf() into one of 10090075Sobrien the underlying constants, and that can be very slow, so we have to 10190075Sobrien precompute them. Whose wonderful idea was it to make all those 10290075Sobrien _constants_ variable at run time, anyway? */ 10390075Sobrien#ifdef USE_TIMES 104132718Skanstatic double ticks_to_msec; 105132718Skan#define TICKS_TO_MSEC (1 / (double)TICKS_PER_SECOND) 10690075Sobrien#endif 10790075Sobrien 10890075Sobrien#ifdef USE_CLOCK 109132718Skanstatic double clocks_to_msec; 110132718Skan#define CLOCKS_TO_MSEC (1 / (double)CLOCKS_PER_SEC) 11190075Sobrien#endif 11290075Sobrien 11390075Sobrien#include "flags.h" 11490075Sobrien#include "timevar.h" 11590075Sobrien 116132718Skanstatic bool timevar_enable; 117132718Skan 11890075Sobrien/* See timevar.h for an explanation of timing variables. */ 11990075Sobrien 12090075Sobrien/* A timing variable. */ 12190075Sobrien 12290075Sobrienstruct timevar_def 12390075Sobrien{ 12490075Sobrien /* Elapsed time for this variable. */ 12590075Sobrien struct timevar_time_def elapsed; 12690075Sobrien 12790075Sobrien /* If this variable is timed independently of the timing stack, 12890075Sobrien using timevar_start, this contains the start time. */ 12990075Sobrien struct timevar_time_def start_time; 13090075Sobrien 13190075Sobrien /* The name of this timing variable. */ 13290075Sobrien const char *name; 13390075Sobrien 134132718Skan /* Nonzero if this timing variable is running as a standalone 13590075Sobrien timer. */ 13690075Sobrien unsigned standalone : 1; 13790075Sobrien 138132718Skan /* Nonzero if this timing variable was ever started or pushed onto 13990075Sobrien the timing stack. */ 14090075Sobrien unsigned used : 1; 14190075Sobrien}; 14290075Sobrien 14390075Sobrien/* An element on the timing stack. Elapsed time is attributed to the 14490075Sobrien topmost timing variable on the stack. */ 14590075Sobrien 14690075Sobrienstruct timevar_stack_def 14790075Sobrien{ 14890075Sobrien /* The timing variable at this stack level. */ 14990075Sobrien struct timevar_def *timevar; 15090075Sobrien 15190075Sobrien /* The next lower timing variable context in the stack. */ 15290075Sobrien struct timevar_stack_def *next; 15390075Sobrien}; 15490075Sobrien 15590075Sobrien/* Declared timing variables. Constructed from the contents of 15690075Sobrien timevar.def. */ 15790075Sobrienstatic struct timevar_def timevars[TIMEVAR_LAST]; 15890075Sobrien 15990075Sobrien/* The top of the timing stack. */ 16090075Sobrienstatic struct timevar_stack_def *stack; 16190075Sobrien 16290075Sobrien/* A list of unused (i.e. allocated and subsequently popped) 16390075Sobrien timevar_stack_def instances. */ 16490075Sobrienstatic struct timevar_stack_def *unused_stack_instances; 16590075Sobrien 16690075Sobrien/* The time at which the topmost element on the timing stack was 16790075Sobrien pushed. Time elapsed since then is attributed to the topmost 16890075Sobrien element. */ 16990075Sobrienstatic struct timevar_time_def start_time; 17090075Sobrien 171132718Skanstatic void get_time (struct timevar_time_def *); 172132718Skanstatic void timevar_accumulate (struct timevar_time_def *, 173132718Skan struct timevar_time_def *, 174132718Skan struct timevar_time_def *); 17590075Sobrien 17690075Sobrien/* Fill the current times into TIME. The definition of this function 17790075Sobrien also defines any or all of the HAVE_USER_TIME, HAVE_SYS_TIME, and 178117395Skan HAVE_WALL_TIME macros. */ 17990075Sobrien 18090075Sobrienstatic void 181132718Skanget_time (struct timevar_time_def *now) 18290075Sobrien{ 18390075Sobrien now->user = 0; 18490075Sobrien now->sys = 0; 18590075Sobrien now->wall = 0; 18690075Sobrien 187132718Skan if (!timevar_enable) 18890075Sobrien return; 18990075Sobrien 19090075Sobrien { 19190075Sobrien#ifdef USE_TIMES 19290075Sobrien struct tms tms; 19390075Sobrien now->wall = times (&tms) * ticks_to_msec; 19490075Sobrien now->user = tms.tms_utime * ticks_to_msec; 19590075Sobrien now->sys = tms.tms_stime * ticks_to_msec; 19690075Sobrien#endif 19790075Sobrien#ifdef USE_GETRUSAGE 19890075Sobrien struct rusage rusage; 19990075Sobrien getrusage (RUSAGE_SELF, &rusage); 20090075Sobrien now->user = rusage.ru_utime.tv_sec + rusage.ru_utime.tv_usec * 1e-6; 20190075Sobrien now->sys = rusage.ru_stime.tv_sec + rusage.ru_stime.tv_usec * 1e-6; 20290075Sobrien#endif 20390075Sobrien#ifdef USE_CLOCK 20490075Sobrien now->user = clock () * clocks_to_msec; 20590075Sobrien#endif 20690075Sobrien } 20790075Sobrien} 20890075Sobrien 20990075Sobrien/* Add the difference between STOP_TIME and START_TIME to TIMER. */ 21090075Sobrien 211117395Skanstatic void 212132718Skantimevar_accumulate (struct timevar_time_def *timer, 213132718Skan struct timevar_time_def *start_time, 214132718Skan struct timevar_time_def *stop_time) 21590075Sobrien{ 21690075Sobrien timer->user += stop_time->user - start_time->user; 21790075Sobrien timer->sys += stop_time->sys - start_time->sys; 21890075Sobrien timer->wall += stop_time->wall - start_time->wall; 21990075Sobrien} 22090075Sobrien 22190075Sobrien/* Initialize timing variables. */ 22290075Sobrien 22390075Sobrienvoid 224132718Skantimevar_init (void) 22590075Sobrien{ 226132718Skan timevar_enable = true; 22790075Sobrien 22890075Sobrien /* Zero all elapsed times. */ 229132718Skan memset (timevars, 0, sizeof (timevars)); 23090075Sobrien 23190075Sobrien /* Initialize the names of timing variables. */ 23290075Sobrien#define DEFTIMEVAR(identifier__, name__) \ 23390075Sobrien timevars[identifier__].name = name__; 23490075Sobrien#include "timevar.def" 23590075Sobrien#undef DEFTIMEVAR 23690075Sobrien 23790075Sobrien#ifdef USE_TIMES 23890075Sobrien ticks_to_msec = TICKS_TO_MSEC; 23990075Sobrien#endif 24090075Sobrien#ifdef USE_CLOCK 24190075Sobrien clocks_to_msec = CLOCKS_TO_MSEC; 24290075Sobrien#endif 24390075Sobrien} 24490075Sobrien 24590075Sobrien/* Push TIMEVAR onto the timing stack. No further elapsed time is 24690075Sobrien attributed to the previous topmost timing variable on the stack; 24790075Sobrien subsequent elapsed time is attributed to TIMEVAR, until it is 248117395Skan popped or another element is pushed on top. 24990075Sobrien 25090075Sobrien TIMEVAR cannot be running as a standalone timer. */ 25190075Sobrien 25290075Sobrienvoid 253132718Skantimevar_push (timevar_id_t timevar) 25490075Sobrien{ 25590075Sobrien struct timevar_def *tv = &timevars[timevar]; 25690075Sobrien struct timevar_stack_def *context; 25790075Sobrien struct timevar_time_def now; 25890075Sobrien 259132718Skan if (!timevar_enable) 26090075Sobrien return; 26190075Sobrien 26290075Sobrien /* Mark this timing variable as used. */ 26390075Sobrien tv->used = 1; 26490075Sobrien 26590075Sobrien /* Can't push a standalone timer. */ 26690075Sobrien if (tv->standalone) 26790075Sobrien abort (); 26890075Sobrien 26990075Sobrien /* What time is it? */ 27090075Sobrien get_time (&now); 27190075Sobrien 27290075Sobrien /* If the stack isn't empty, attribute the current elapsed time to 27390075Sobrien the old topmost element. */ 27490075Sobrien if (stack) 27590075Sobrien timevar_accumulate (&stack->timevar->elapsed, &start_time, &now); 27690075Sobrien 27790075Sobrien /* Reset the start time; from now on, time is attributed to 27890075Sobrien TIMEVAR. */ 27990075Sobrien start_time = now; 28090075Sobrien 28190075Sobrien /* See if we have a previously-allocated stack instance. If so, 28290075Sobrien take it off the list. If not, malloc a new one. */ 283117395Skan if (unused_stack_instances != NULL) 28490075Sobrien { 28590075Sobrien context = unused_stack_instances; 28690075Sobrien unused_stack_instances = unused_stack_instances->next; 28790075Sobrien } 28890075Sobrien else 289132718Skan context = xmalloc (sizeof (struct timevar_stack_def)); 29090075Sobrien 29190075Sobrien /* Fill it in and put it on the stack. */ 29290075Sobrien context->timevar = tv; 29390075Sobrien context->next = stack; 29490075Sobrien stack = context; 29590075Sobrien} 29690075Sobrien 29790075Sobrien/* Pop the topmost timing variable element off the timing stack. The 29890075Sobrien popped variable must be TIMEVAR. Elapsed time since the that 29990075Sobrien element was pushed on, or since it was last exposed on top of the 30090075Sobrien stack when the element above it was popped off, is credited to that 30190075Sobrien timing variable. */ 30290075Sobrien 30390075Sobrienvoid 304132718Skantimevar_pop (timevar_id_t timevar) 30590075Sobrien{ 30690075Sobrien struct timevar_time_def now; 30790075Sobrien struct timevar_stack_def *popped = stack; 30890075Sobrien 309132718Skan if (!timevar_enable) 31090075Sobrien return; 31190075Sobrien 31290075Sobrien if (&timevars[timevar] != stack->timevar) 313117395Skan { 314117395Skan sorry ("cannot timevar_pop '%s' when top of timevars stack is '%s'", 315117395Skan timevars[timevar].name, stack->timevar->name); 316117395Skan abort (); 317117395Skan } 31890075Sobrien 31990075Sobrien /* What time is it? */ 32090075Sobrien get_time (&now); 32190075Sobrien 32290075Sobrien /* Attribute the elapsed time to the element we're popping. */ 32390075Sobrien timevar_accumulate (&popped->timevar->elapsed, &start_time, &now); 32490075Sobrien 32590075Sobrien /* Reset the start time; from now on, time is attributed to the 32690075Sobrien element just exposed on the stack. */ 32790075Sobrien start_time = now; 32890075Sobrien 32990075Sobrien /* Take the item off the stack. */ 33090075Sobrien stack = stack->next; 33190075Sobrien 33290075Sobrien /* Don't delete the stack element; instead, add it to the list of 33390075Sobrien unused elements for later use. */ 33490075Sobrien popped->next = unused_stack_instances; 33590075Sobrien unused_stack_instances = popped; 33690075Sobrien} 33790075Sobrien 33890075Sobrien/* Start timing TIMEVAR independently of the timing stack. Elapsed 33990075Sobrien time until timevar_stop is called for the same timing variable is 34090075Sobrien attributed to TIMEVAR. */ 34190075Sobrien 34290075Sobrienvoid 343132718Skantimevar_start (timevar_id_t timevar) 34490075Sobrien{ 34590075Sobrien struct timevar_def *tv = &timevars[timevar]; 34690075Sobrien 347132718Skan if (!timevar_enable) 34890075Sobrien return; 34990075Sobrien 35090075Sobrien /* Mark this timing variable as used. */ 35190075Sobrien tv->used = 1; 35290075Sobrien 35390075Sobrien /* Don't allow the same timing variable to be started more than 35490075Sobrien once. */ 35590075Sobrien if (tv->standalone) 35690075Sobrien abort (); 35790075Sobrien tv->standalone = 1; 35890075Sobrien 35990075Sobrien get_time (&tv->start_time); 36090075Sobrien} 36190075Sobrien 36290075Sobrien/* Stop timing TIMEVAR. Time elapsed since timevar_start was called 36390075Sobrien is attributed to it. */ 36490075Sobrien 36590075Sobrienvoid 366132718Skantimevar_stop (timevar_id_t timevar) 36790075Sobrien{ 36890075Sobrien struct timevar_def *tv = &timevars[timevar]; 36990075Sobrien struct timevar_time_def now; 37090075Sobrien 371132718Skan if (!timevar_enable) 37290075Sobrien return; 37390075Sobrien 37490075Sobrien /* TIMEVAR must have been started via timevar_start. */ 37590075Sobrien if (!tv->standalone) 37690075Sobrien abort (); 37790075Sobrien 37890075Sobrien get_time (&now); 37990075Sobrien timevar_accumulate (&tv->elapsed, &tv->start_time, &now); 38090075Sobrien} 38190075Sobrien 38290075Sobrien/* Fill the elapsed time for TIMEVAR into ELAPSED. Returns 38390075Sobrien update-to-date information even if TIMEVAR is currently running. */ 38490075Sobrien 38590075Sobrienvoid 386132718Skantimevar_get (timevar_id_t timevar, struct timevar_time_def *elapsed) 38790075Sobrien{ 38890075Sobrien struct timevar_def *tv = &timevars[timevar]; 38990075Sobrien struct timevar_time_def now; 39090075Sobrien 39190075Sobrien *elapsed = tv->elapsed; 392117395Skan 39390075Sobrien /* Is TIMEVAR currently running as a standalone timer? */ 39490075Sobrien if (tv->standalone) 39590075Sobrien { 39690075Sobrien get_time (&now); 39790075Sobrien timevar_accumulate (elapsed, &tv->start_time, &now); 39890075Sobrien } 39990075Sobrien /* Or is TIMEVAR at the top of the timer stack? */ 40090075Sobrien else if (stack->timevar == tv) 40190075Sobrien { 40290075Sobrien get_time (&now); 40390075Sobrien timevar_accumulate (elapsed, &start_time, &now); 40490075Sobrien } 40590075Sobrien} 40690075Sobrien 40790075Sobrien/* Summarize timing variables to FP. The timing variable TV_TOTAL has 40890075Sobrien a special meaning -- it's considered to be the total elapsed time, 40990075Sobrien for normalizing the others, and is displayed last. */ 41090075Sobrien 41190075Sobrienvoid 412132718Skantimevar_print (FILE *fp) 41390075Sobrien{ 41490075Sobrien /* Only print stuff if we have some sort of time information. */ 41590075Sobrien#if defined (HAVE_USER_TIME) || defined (HAVE_SYS_TIME) || defined (HAVE_WALL_TIME) 41690075Sobrien unsigned int /* timevar_id_t */ id; 41790075Sobrien struct timevar_time_def *total = &timevars[TV_TOTAL].elapsed; 41890075Sobrien struct timevar_time_def now; 41990075Sobrien 420132718Skan if (!timevar_enable) 42190075Sobrien return; 42290075Sobrien 42390075Sobrien /* Update timing information in case we're calling this from GDB. */ 42490075Sobrien 42590075Sobrien if (fp == 0) 42690075Sobrien fp = stderr; 42790075Sobrien 42890075Sobrien /* What time is it? */ 42990075Sobrien get_time (&now); 43090075Sobrien 43190075Sobrien /* If the stack isn't empty, attribute the current elapsed time to 43290075Sobrien the old topmost element. */ 43390075Sobrien if (stack) 43490075Sobrien timevar_accumulate (&stack->timevar->elapsed, &start_time, &now); 43590075Sobrien 43690075Sobrien /* Reset the start time; from now on, time is attributed to 43790075Sobrien TIMEVAR. */ 43890075Sobrien start_time = now; 43990075Sobrien 44090075Sobrien fputs (_("\nExecution times (seconds)\n"), fp); 44190075Sobrien for (id = 0; id < (unsigned int) TIMEVAR_LAST; ++id) 44290075Sobrien { 44390075Sobrien struct timevar_def *tv = &timevars[(timevar_id_t) id]; 444132718Skan const double tiny = 5e-3; 44590075Sobrien 44690075Sobrien /* Don't print the total execution time here; that goes at the 44790075Sobrien end. */ 44890075Sobrien if ((timevar_id_t) id == TV_TOTAL) 44990075Sobrien continue; 45090075Sobrien 45190075Sobrien /* Don't print timing variables that were never used. */ 45290075Sobrien if (!tv->used) 45390075Sobrien continue; 45490075Sobrien 45590075Sobrien /* Don't print timing variables if we're going to get a row of 45690075Sobrien zeroes. */ 45790075Sobrien if (tv->elapsed.user < tiny 45890075Sobrien && tv->elapsed.sys < tiny 45990075Sobrien && tv->elapsed.wall < tiny) 46090075Sobrien continue; 46190075Sobrien 46290075Sobrien /* The timing variable name. */ 46390075Sobrien fprintf (fp, " %-22s:", tv->name); 46490075Sobrien 46590075Sobrien#ifdef HAVE_USER_TIME 46690075Sobrien /* Print user-mode time for this process. */ 467117395Skan fprintf (fp, "%7.2f (%2.0f%%) usr", 46890075Sobrien tv->elapsed.user, 46990075Sobrien (total->user == 0 ? 0 : tv->elapsed.user / total->user) * 100); 47090075Sobrien#endif /* HAVE_USER_TIME */ 47190075Sobrien 47290075Sobrien#ifdef HAVE_SYS_TIME 47390075Sobrien /* Print system-mode time for this process. */ 474117395Skan fprintf (fp, "%7.2f (%2.0f%%) sys", 47590075Sobrien tv->elapsed.sys, 47690075Sobrien (total->sys == 0 ? 0 : tv->elapsed.sys / total->sys) * 100); 47790075Sobrien#endif /* HAVE_SYS_TIME */ 47890075Sobrien 47990075Sobrien#ifdef HAVE_WALL_TIME 48090075Sobrien /* Print wall clock time elapsed. */ 481117395Skan fprintf (fp, "%7.2f (%2.0f%%) wall", 48290075Sobrien tv->elapsed.wall, 48390075Sobrien (total->wall == 0 ? 0 : tv->elapsed.wall / total->wall) * 100); 48490075Sobrien#endif /* HAVE_WALL_TIME */ 48590075Sobrien 48690075Sobrien putc ('\n', fp); 48790075Sobrien } 48890075Sobrien 48990075Sobrien /* Print total time. */ 49090075Sobrien fputs (_(" TOTAL :"), fp); 49190075Sobrien#ifdef HAVE_USER_TIME 49290075Sobrien fprintf (fp, "%7.2f ", total->user); 493117395Skan#endif 49490075Sobrien#ifdef HAVE_SYS_TIME 49590075Sobrien fprintf (fp, "%7.2f ", total->sys); 49690075Sobrien#endif 49790075Sobrien#ifdef HAVE_WALL_TIME 49890075Sobrien fprintf (fp, "%7.2f\n", total->wall); 49990075Sobrien#endif 500117395Skan 501117395Skan#endif /* defined (HAVE_USER_TIME) || defined (HAVE_SYS_TIME) 50290075Sobrien || defined (HAVE_WALL_TIME) */ 50390075Sobrien} 50490075Sobrien 50590075Sobrien/* Prints a message to stderr stating that time elapsed in STR is 50690075Sobrien TOTAL (given in microseconds). */ 50790075Sobrien 50890075Sobrienvoid 509132718Skanprint_time (const char *str, long total) 51090075Sobrien{ 51190075Sobrien long all_time = get_run_time (); 51290075Sobrien fprintf (stderr, 51390075Sobrien _("time in %s: %ld.%06ld (%ld%%)\n"), 51490075Sobrien str, total / 1000000, total % 1000000, 515117395Skan all_time == 0 ? 0 516117395Skan : (long) (((100.0 * (double) total) / (double) all_time) + .5)); 51790075Sobrien} 518