Администратор тестов UFT

Администратор тестов uft (трассировки пользовательских функций) поддерживает тестирование функций пользовательского пространства, видимых в таблице имен XCOFF процесса. Администратор тестов uft поддерживает только тестовые точки, являющиеся точками входа или выхода и функций с исходным кодом на языках C или FORTRAN, причем в таблице имен могут содержаться идентификаторы с исходным текстом на языках, отличающихся от C или FORTRAN.

С точки зрения пользователя трассировка приложений на Java™ схожа с существующим механизмом трассировки. JVM при этом выполняет большинство задач от имени Probevue.

Администратор тестов uft принимает 5-кортежную спецификацию тестов в следующем формате:

uft:<ИД-процесса>:*:<имя-функции>:<entry|exit>
Прим.: Для администратора тестов uft необходимо указать ИД процесса, который требуется трассировать, и полное имя функции, на точке входа или выхода которой требуется поместить тест.
PID или имя программы

ИД трассируемого процесса или имя тестируемой программы (имя исполняемого файла). Вы можете указать ИД процесса или имя исполняемого файла в двойных кавычках ("/usr/bin/test"), в одинарных кавычках ('/usr/bin/test') или в виде пути к файлу (/usr/bin/test) . Можно указать абсолютный или относительный путь к исполняемому файлу. Также в качестве значения параметра Имя программы можно указать жесткую или символическую ссылку на исполняемый файл. В следующих примерах показаны разные способы задания спецификации теста второго кортежа.

Примеры

@@uft:123450 :*: foo :entry
@@uft : /usr/bin/test:* :foo:entry
@@uft:./test:*:foo:entry
@@uftxlc++:/usr/bin/test:*:foo:exit
@@uftxlc++:"/usr/bin/testxxx":*:foo:exit
@@uft :"/usr/bin/xxx":* :foo:entry
@@uft:'/home/xxx/test':*:func1:entry 
Если /usr/bin/test является исполняемым файлом, а /testln представляет собой ссылку на файл /usr/bin/test (/testln ->/usr/bin/test), то для тестирования всех процессов, запущенных исполняемым файлом /usr/bin/test или с помощью ссылки /testln для этого пользователя выполните следующую команду.

@@uft:/testln:*:foo:entry  
Прим.: В один момент времени пользователь может трассировать исполняемый файл только в одном сеансе.

Кроме того, для администратора тестов uft необходимо, чтобы в третьем поле был помещен символ *, указывающий, что имя функции следует искать во всех модулях, загружаемых в адресное пространство процесса, включая главный исполняемый файл и общие модули. Этим подразумевается, что в случае, если программа содержит более одной функции C с этим именем (например, функции со статическим классом, содержащиеся в различных объектных модулях), то тесты будут применяться к точке входа каждой из этих функций.

Для тестирования функции в модуле необходимо указать название модуля в третьем поле. Синтаксис:

# Функция foo в любом модуле
@@uft:<pid>:*:foo:entry 
# Функция foo в любом модуле любого архива с именем libc.a
@@uft:<pid>:libc.a:foo:entry 
# Функция foo в модуле shr.o любого архива с именем libc.a
@@uft:<pid>:libc.a(shr.o):foo:entry	  

Имя функции в четвертой записи можно указать в виде расширенного регулярного выражения (ERE). Выражение ERE необходимо заключить в "/ и /" , например "/<ERE>/".

Когда имя функции указано в виде ERE, тестируются все функции в указанном модуле, имя которых соответствует выражению ERE.
 /* Тестируются точки входа всех функций libc.a, начинающиеся с “malloc” */
@@uft:$__CPID:libc.a: “/^malloc.*/”:entry      
/* Тестируются точки выхода всех функций в a.out */
@@uft:$__CPID:a.out:”/.*/”:exit

При тестировании функций, имя которых соответствует регулярному выражению, нельзя получить доступ к параметрам функций. Для вывода функции и ее аргументов можно использовать функцию print_args. Тип аргументов при выводе будет взят из таблицы обратной трассировки.

При тестировании точки выхода функций, имя которых соответствует регулярному выражению, нельзя получить доступ к возвращаемому значению.

Probevue поддерживает включение тестов в нескольких процессах одновременно. Однако потребуются права доступа даже для тестирования собственных процессов.

Probevue вводит ограничение, делающее невозможной отладку процессов с тестами пользовательского пространства с помощью API на основе ptrace или procfs.

Как сказано выше, администратор тестов uft поддерживает тесты в общих модулях, таких как модули общих библиотек. В следующем сценарии показан пример трассировки мьютекс-операции путем включения тестов в функциях блокировки и разблокировки мьютекса библиотеки нити.

/* pthreadlocks.e */
/* Трассировка мьютекс-операции pthread для многонитевого процесса */
/* Следующие определения взяты из /usr/include/sys/types.h */

typedef long long pid_t;
typedef long long thread_t;

typedef struct {
	int	__pt_mutexattr_status;	
	int	__pt_mutexattr_pshared;	
	int	__pt_mutexattr_type;
} pthread_mutexattr_t;

typedef struct __thrq_elt thrq_elt_t;

struct __thrq_elt {
	thrq_elt_t	*__thrq_next;
	thrq_elt_t	*__thrq_prev;
};

typedef volatile unsigned char _simplelock_t;

typedef struct __lwp_mutex {
	char		__wanted;
	_simplelock_t	__lock;
} lwp_mutex_t;

typedef struct {
	lwp_mutex_t		__m_lmutex;
	lwp_mutex_t		__m_sync_lock;
	int			__m_type;
	thrq_elt_t		__m_sleepq;
	int			__filler[2];
} mutex_t;

typedef struct {
	mutex_t			__pt_mutex_mutex;
	pid_t			__pt_mutex_pid;
	thread_t		__pt_mutex_owner;
	int			__pt_mutex_depth;
	pthread_mutexattr_t	__pt_mutex_attr;
} pthread_mutex_t;

int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);

@@uft:$__CPID:*:pthread_mutex_lock:entry
{
	printf("thread %d: mutex 0x%08x locked\n", __tid, __arg1);
}

@@uft:$__CPID:*:pthread_mutex_unlock:entry
{
	printf("thread %d: mutex 0x%08x unlocked\n", __tid, __arg1);
}
  • Пользователь должен связать типы данных языка Fortran с типами данных ProbeVue и использовать данную привязку в сценарии. Ниже приведена таблица соответствия между базовыми типами данных языка Fortran и типами данных ProbeVue.
    Табл. 1. Соответствие типов данных языка Fortran и ProveVue
    Тип данных языка Fortran Тип данных ProbeVue
    INTEGER * 2 short
    INTEGER * 4 int/long
    INTEGER * 8 long long
    REAL float
    DOUBLE PRECISION double
    COMPLEX Соответствующий тип данных отсутствует. Данный тип данных необходимо преобразовать в следующую структуру:
    typedef struct complex {
    float a;
    float b;
    } COMPLEX;
    LOGICAL int (стандарт языка Fortran требует, чтобы логические переменные занимали в памяти столько же места, сколько и переменные INTEGER/REAL)
    CHARACTER char
    BYTE signed char
  • В языке Fortran скалярные аргументы внутренних процедур передаются по значению, остальные - по ссылке. Доступ к аргументам, передающимся по ссылке, должен осуществляться с помощью copy_userdata(). Дополнительная информация о связях аргументов в языке Fortran приведена в разделе Связи аргументов.
  • Названия процедур в Fortran не учитывают регистр символов. Но в сценарии ProbeVue имена данных процедур необходимо указывать в нижнем регистре.
    Следующий пример демонстрирует связь между типами данных Fortran и ProbeVue:
    /* cmp_calc.e */
    /* Трассировка процедур Fortran 
    cmp_calc(COMPLEX, INTEGER) и 
    cmplxd(void) */
    
    typedef struct complex{
            float a;
            float b;
            } COMPLEX;
    
    typedef int INTEGER;
    
    /* в качестве аргументов используются указатели, передаваемые по ссылке */
    void cmp_calc(COMPLEX *, INTEGER *);  
    void cmplxd();
    
    @@uft:$__CPID:*:cmplxd:entry
    {
    printf("На входе cmplxd \n");
    }
    
    @@uft:$__CPID:*:cmp_calc:entry
    {
    COMPLEX c;
    int     i;
    copy_userdata(__arg1, c);
    copy_userdata(__arg2, i);
    printf("%10.7f+j%9.7f  %d \n", c.a,c.b,i);
    }
  • Fortran хранит массивы с помощью развертывания по столбцам (column-major), а ProbeVue - с помощью развертывания по строкам (row-major). Ниже представлен пример сценария для извлечения элементов массива.
    /* array.e*/
    /* Сценарий ProbeVue для тестирования программы на Fortran array.f */
    
    void displayarray(int **, int, int);
    @@uft:$__CPID:*:displayarray:entry
    {
    int a[5][4];		/* размеры строк и столбцов меняются местами */
    copy_userdata(__arg1, a);
    /* выводится первая строка */
    printf("%d %d %d \n”, a[0][0], a[1][0], a[2][0]);
    /* для вывода второй строки */
    printf(“%d %d %d\n", a[0][1], a[1][1], a[2][1]);
    }
    
    /* программа Fortran array.f */
    
    PROGRAM ARRAY_PGM
    IMPLICIT NONE 
    INTEGER, DIMENSION(1:4,1:5) :: Array 
    INTEGER :: RowSize, ColumnSize
    CALL ReadArray(Array, RowSize, ColumnSize) 
    CALL DisplayArray(Array, RowSize, ColumnSize) 
    CONTAINS
    SUBROUTINE ReadArray(Array, Rows, Columns)
    IMPLICIT NONE
    INTEGER, DIMENSION(1:,1:), INTENT(OUT) :: Array
    INTEGER, INTENT(OUT) :: Rows, Columns
    INTEGER :: i, j
    READ(*,*) Rows, Columns
    DO i = 1, Rows
    READ(*,*) (Array(i,j), j=1, Columns)
    END DO
    END SUBROUTINE ReadArray
    SUBROUTINE DisplayArray(Array, Rows, Columns) 
    IMPLICIT NONE 
    INTEGER, DIMENSION(1:,1:), INTENT(IN) :: Array
    INTEGER, INTENT(IN) :: Rows, Columns 
    INTEGER :: i, j 
    DO i = 1, Rows 
    WRITE(*,*) (Array(i,j), j=1, Columns )
    END DO 
    END SUBROUTINE DisplayArray
    END PROGRAM ARRAY_PGM
  • Встроенные функции нельзя тестировать с помощью ProbeVue . Тестировать можно все процедуры FORTRAN, перечисленные в таблице имен XCOFF. ProbeVue использует данную таблицу для получения сведений о том, где находятся указанные процедуры. Пользователь должен предоставить прототип процедуры. ProbeVue пытается получить доступ к аргументам на основе указанного прототипа. В случае использования компилятора, изменяющего имена процедур, необходимо указать измененное имя. Необходимо убедиться в том, что прототип с функциями FORTRAN соответствующим образом преобразовывается в прототип с функциями на C. См. соглашения по связыванию для передаваемых аргументов и возвращаемых значений в разделе Передача данных из одного языка в другой. Это продемонстрировано в следующем примере:
    /* Программа на Fortran ext_op.f */
    /* Оператор “*” перегружен для умножения рациональных чисел */
    MODULE rational_arithmetic
    IMPLICIT NONE
            TYPE RATNUM
                    INTEGER :: num, den
            END TYPE RATNUM
            INTERFACE OPERATOR (*)
                    MODULE PROCEDURE rat_rat, int_rat, rat_int
            END INTERFACE
            CONTAINS
            FUNCTION rat_rat(l,r) ! rat * rat
                    TYPE(RATNUM), INTENT(IN) :: l,r
                    TYPE(RATNUM) :: val,rat_rat
                    val.num=l.num*r.num
                    val.den=l.den*r.den
                    rat_rat=val
            END FUNCTION rat_rat
            FUNCTION int_rat(l,r) ! int * rat
                    INTEGER, INTENT(IN) :: l
                    TYPE(RATNUM), INTENT(IN) :: r
                    TYPE(RATNUM) :: val,int_rat
                    val.num=l*r.num
                    val.den=r.den
                    int_rat=val
            END FUNCTION int_rat
            FUNCTION rat_int(l,r) ! rat * int
                    TYPE(RATNUM), INTENT(IN) :: l
                    INTEGER, INTENT(IN) :: r
                    TYPE(RATNUM) :: val,rat_int
                    val.num=l.num*r
                    val.den=l.den
                    rat_int=val
            END FUNCTION rat_int
    END MODULE rational_arithmetic
    PROGRAM Main1
    Use rational_arithmetic
    IMPLICIT NONE
    	TYPE(RATNUM) :: l,r,l1
    	l.num=10
            l.den=11
            r.num=3
            r.den=4
            L1=l*r
    END PROGRAM Main1
    
    /* ext_op.e */
    /* Сценарий ProbeVue, вызываемый при использовании оператора “*”
        для умножения рациональных чисел в ext_op.f */
    
    struct rat
    {
            int num;
            int den;
    };
    struct rat rat;
    void __rational_arithmetic_NMOD_rat_rat(struct rat*,
    	struct rat*,struct rat*); 
    /* Обратите внимание, что приведено измененное имя функции. */    
    /* Кроме того, возвращаемая структура будет отправлена в буфер, адрес которого задан в первом аргументе. */
    /* Первый явный параметр находится во втором аргументе. */
    @@BEGIN
    {
            struct rat* rat3;
    }
    @@uft:$__CPID:*:__rational_arithmetic_NMOD_rat_rat:entry
    {
    	struct rat rat1,rat2;
            copy_userdata((struct rat *)__arg2,rat1);
            copy_userdata((struct rat *)__arg3,rat2);
            rat3=__arg1;
    	/* Адрес буфера, в котором будет храниться возвращенная структура, сохраняется при входе функции */
            printf("Argument Passed rat_rat = %d:%d,%d:%d\n",rat1.num,rat1.den,rat2.num,rat2.den);
    }
    @@uft:$__CPID:*:__rational_arithmetic_NMOD_rat_rat:exit
    {
            struct rat rrat;
            copy_userdata((struct rat *)rat3,rrat);	
            /* Для обращения к структуре используется сохраненный адрес буфера */
            printf("Return from rat_rat = %d:%d\n",rrat.num,rrat.den);
            exit();
    }
  • ProbeVue не поддерживает прямое включения в сценарий заголовочных файлов Fortran. Связь между типами данных Fortran и ProbeVue можно задать в заголовочном файле ProbeVue. Этот файл можно указать с помощью опции "-I".