Higher Education Statistics in C Language Linguagens de Programação Docente: Professor Doutor José Jasnau Caeiro Discente: Rafael Montegordo Félix nº 6209 Abril, 2011 Índice Introdução ................................................................................................................................. 3 API Utilizadas ............................................................................................................................. 4 API SQLite/C .......................................................................................................................... 5 Python/C API ......................................................................................................................... 5 Funções ..................................................................................................................................... 6 Qsort() – Funções de Comparação ........................................................................................ 6 Funções Callback ................................................................................................................... 6 void cleanFile() ...................................................................................................................... 7 PyObject* nDocentesPerYear(PyObject* orderBy)............................................................... 7 PyObject* listInstYear(PyObject* yearList) ........................................................................... 7 PyObject* nDocentesPerInstPerYear(PyObject* yearList).................................................... 8 PyObject* nDocentesPerDegreePerYear(PyObject* yearList) .............................................. 8 PyObject* nDocentesPerDegreePerInstPerYear(PyObject* yearList) .................................. 8 listDegreeHolder(PyObject* yearList, PyObject* degree) .................................................... 9 teacherHiringPerInst() ........................................................................................................... 9 GPROF ..................................................................................................................................... 10 Conclusão ................................................................................................................................ 11 Bibliografia .............................................................................................................................. 12 Introdução Este trabalho tem como objectivo a criação de um módulo que poderá ser mais tarde utilizado através de um programa criado na linguagem Python. Para a criação deste módulo foi utilizada a linguagem C, uma linguagem imperativa cujos seus pontos de design foram para ele ser compilado, fornecendo acesso de baixo nível à memória e baixos requerimentos do hardware, tornando-a assim uma linguagem bastante rápida. Para a criação deste módulo foi também utilizada a biblioteca de sqlite para a linguagem C, para que fosse possível a recolha da informação de uma base de dados. Foi também necessário consultar a documentação da Python/C API para que fosse possível retornar os resultados obtidos no módulo programado em C para o programa em Python. Ficheiros O programa foi dividido em ficheiros para que a sua leitura seja mais fácil. Datacolletion.c Neste ficheiro é possível encontrar as funções principais que geram as estatísticas e listas e as devolvem para que possam ser utilizadas no Python. Gera também um ficheiro de texto com a informação recolhida das várias funções executadas. Functions.c Contém as funções que auxiliam as funções principais, as funções que efectuam o tratamento dos dados, como as funções de comparação utilizadas no qsort e as funções de “callback” utilizadas pelo sqlite3_exec. Funcoes.h Ficheiro header (interface) do anterior. Neste ficheiro são definidas as estruturas e as funções utilizadas pelo nosso programa indicando o cabeçalho das mesmas, sendo necessário de pois efectuar um “include ” deste ficheiro nos que necessitarem de utilizar estas mesmas funções. API Utilizadas API SQLite/C Em todas as funções que seja necessário aceder a base de dados, foi utilizada a API SQLite/C, para poder efectuar consultas e recolher informação da base de dados. São utilizadas três funções desta API, a função sqlite3_open para abrir a base de dados, sqlite3_exec para efectuar a consulta e por ultimo uma função de “callback” que é executada por cada linha de informação existente na consulta efectuada a base de dados. Esta função de “calback” pode ser alterada de maneira a efectuar o pretendido pelo programador. Tem também a possibilidade de receber por parâmetro um ponteiro para um variável de qualquer tipo, para que o utilizador possa armazenar a informação e não tenha que recorrer a variáveis globais. Python/C API Esta API permite que variáveis da linguagem C sejam convertidas para objectos da linguagem Python, criando assim a possibilidade de efectuar passagem de informação entre as duas linguagens. Neste trabalho foram utilizadas varias funções, como por exemplo a PyList_New() que permite criar uma lista que poderá ser utilizada no Python. Muitas outras foram utilizadas, para converter inteiros, strings, entre outros. Toda esta informação está disponível no site[1] do Python. Funções Qsort() – Funções de Comparação Qsort() é a função utilizada para ordenar a informação. Esta função recebe como parâmetros um array, o tamanho do array, o tipo de dados do array e uma função para efectuar a ordenação. É utilizada em praticamente todas as outras funções, alterando-se apenas a função de ordenação. Neste trabalho temos 4 funções de comparação: - comparenNumberPerYear(struct NumberPerYear *elem1, struct NumberPerYear *elem2) - compNDocentesPerInstPerYear(struct nDocentesPerInstPerYear *elem1, struct nDocentesPerInstPerYear *elem2) - compNDocentesPerDegreePerInstPerYear(struct nDocentesPerDegreePerInstPerYear *elem1, struct nDocentesPerDegreePerInstPerYear *elem2) - PyStringCmp(PyObject** elem1, PyObject** elem2) Nas primeiras 3 a única diferença e o tipo de elemento que recebe por parâmetro, pois para desenvolver as funções necessárias foi utilizado estruturas para guardar os dados, e cada função de comparação recebe uma estrutura de tipo diferente. Ambas as 3 comparam números e organiza-os do menor para o maior. A PyStringCmp recebe elementos de Python (PyObjects), neste caso strings, converte-os para array de chars através da função PyString_AsString e compara as strings com recurso a função strcmp(), organizando assim a informação por ordem alfabética. A organização por ordem alfabética tem um pequeno erro, pois as palavras que começam com acento na primeira letra são colocadas no fim da lista, mesmo sendo a primeira letra um ‘Á’. Funções Callback Como já foi referido em cima, as funções de “callback“, são utilizadas pelo sqlite3_exec para guardar a informação da consulta á base de dados em variáveis para que seja possível a manipulação desses dados. Temos 4 funções de “callback”: callbackInt(void **NotUsed, int argc, char **argv, char **azColName) callbackPyList(void **NotUsed, int argc, char **argv, char **azColName) callBack_NDIY(struct nDocentesPerInstPerYear **NotUsed, int argc, char **argv, char **azColName) callBack_NDDIY(struct nDocentesPerDegreePerInstPerYear **NotUsed, int argc, char **argv, char **azColName) Nas funções de “callback” a variável NotUsed, referida em todas as funções, é a variável que nos podemos enviar para o “callback” para guardar os dados, esta variável pode ser de qualquer tipo. Neste caso as variáveis NotUsed são apontadores para os apontadores da variável que nós passamos para guardar os dados. Isto é muito útil pois faz com que seja possível que na callBack_NDIY e na callBack_NDDIY seja possível percorrer um array de estruturas, para que possamos gravar as várias linhas de informação recolhida da base de dados, uma linha em cada posição do array. A função callbackInt apenas guarda a informação de um inteiro e a callbackPyList vai introduzindo a informação numa lista de objectos Python. void cleanFile() Toda a informação é guardada num único ficheiro. Esta função pode ser utilizada para limpar esse mesmo ficheiro, caso seja necessário escrever nova informação. PyObject* nDocentesPerYear(PyObject* orderBy) Esta função é responsável por retornar uma lista de tuplos, onde cada tuplo contém o ano e o número total de docentes nesse mesmo ano. A informação é obtida através de uma consulta a base de dados, utilizando a API SQlite. Utiliza a função callbackInt para guardar a informação numa variável. Esta função recebe também uma string de Python que indica se o utilizador quer ordenar a informação por número de docentes ou por ano (“NDOCENTES” – ordena pelo nº de docentes, “” – ordena por ano). Para efectuar esta ordenação foi utilizada a função qsort() com a função de comparação comparenNumberPerYear. Toda esta informação está convertida através da Python/C API para objectos de Python, para que possa ser tratada pelo software desenvolvido na linguagem Python. Toda a informação recolhida é também escrita num ficheiro para o utilizador poder aceder. PyObject* listInstYear(PyObject* yearList) Esta função retorna uma lista de tuplos, onde cada tuplo contém o ano e uma lista com todas as instituições desse ano. Toda esta informação está convertida através da Python/C API para objectos de Python, para que possa ser tratada pelo software desenvolvido na linguagem Python. Esta função recebe do software de Python uma lista de anos, para que o utilizador possa indicar de quais ou qual o ano que pretende informação. A função de “callback” utilizada é a callbackPyList. Para efectuar a ordenação da informação utilizado uma aboradagem diferente, pois tínhamos uma lista de objectos Python em vez das estruturas utilizadas nas outras funções. Foi então necessário a criação de uma array para guardar esses objectos, sendo depois utilizada a função qsort() com a função de comparação PyStringCmp. Toda a informação recolhida é também escrita num ficheiro para o utilizador poder aceder. PyObject* nDocentesPerInstPerYear(PyObject* yearList) PyObject* nDocentesPerDegreePerYear(PyObject* yearList) Estas funções retornam uma lista de tuplos, onde cada tuplo contém o ano, a instituição/Grau e o número de docentes nessa instituição. Toda esta informação está convertida através da Python/C API para objectos de Python, para que possa ser tratada pelo software desenvolvido na linguagem Python. Esta função recebe do software de Python uma lista de anos, para que o utilizador possa indicar de quais ou qual o ano que pretende informação. A função de “callback” utilizada é a callBack_NDIY. Para efectuar a ordenação da informação, nesta função foi utilizado novamente o qsort() com a função de comparação compNDocentesPerInstPerYear. Toda a informação recolhida é também escrita num ficheiro para o utilizador poder aceder. PyObject* nDocentesPerDegreePerInstPerYear(PyObject* yearList) Esta função retorna uma lista de tuplos, onde cada tuplo contém ano, instituição, grau e número de docente. Para calcular o espaço a alocar em memória para o array de estruturas que guardará esta informação foi utilizada a funcção nDegreeInstYear(yearList), que retorna um array o número de elementos que será necessário alocar no array de estruturas por ano. Foi efectuado também uma da referência do primeiro elemento do array de estruturas, para poder depois no final libertar o espaço alocado. A função de “callback” utilizada é a callBack_NDDIY. Para efectuar a ordenação da informação, nesta função foi utilizado novamente o qsort() com a função de comparação compNDocentesPerDegreePerInstPerYear. Toda a informação recolhida é também escrita num ficheiro para o utilizador poder aceder. listDegreeHolder(PyObject* yearList, PyObject* degree) Esta função retorna uma lista de tuplos, onde cada tuplo contém ano e uma lista com onome dos docentes que detêm aquele grau de ensino. Tal como na função listInstYear() o método de ordenação foi novamente a criação de um array de PyObjects para colocar os elementos da lista de Python, utilizando posteriormente a função qsort() com a função de comparação PyStringCmp. Toda a informação recolhida é também escrita num ficheiro para o utilizador poder aceder. teacherHiringPerInst() Esta função verifica em todas as instituições quais as diferenças entre o número de docentes nos diversos anos. Para efectuar esta verificação recorre a utilização de duas funções, sendo elas a teacherHiring(PyObject* inst) e listInstNoWrite(PyObject* year). A função listInstNoWrite recebe como parâmetro um ano e retorna a lista de todas as instituições. Cada elemento desta lista é depois enviado para a função teacherHiring que recebe como parâmetro o nome de uma instituição e calcula então a diferença entre o número de docentes da instituição por ano e retorna uma lista com toda essa informação. Esta função escreve também os resultados obtidos num ficheiro. Visto esta função utilizar outras para efectuar os cálculos não é necessário a utilização de nenhuma função para ordenar, pois toda a informação já vem ordenada. GPROF Gprof é uma ferramenta para análise dinâmica da execução de programas escritos em linguagem C, Fortran e Pascal. O propósito usual desse tipo de análise é determinar o quanto de recurso computacional é consumido por cada parte do código, com o objectivo de optimizar o tempo de execução e diminuir quando possível o consumo de memória. Essa ferramenta pode ser usada em conjunto com o GCC. O Gprof, como o docente referiu, utiliza bibliotecas estáticas não funcionado muito bem com os PyObjects. Contudo muitas das funcionalidades do trabalho desenvolvido necessitam de PyObjects para funcionar, pois existem várias funções que recebem PyLists e outros objectos de python. Retirar todos os objectos de python do trabalho iria requerer que cria-se novas funções que não dependessem desses mesmos objectos para funcionarem. Conclusão A realização deste trabalho foi bastante interessante pois nunca tinha efectuado uma “mistura” de linguagens que são completamente diferentes, pois o C é uma linguagem de baixo nível onde não existe objectos e Python é uma linguagem de alto nível que está orientada para objectos. Gostei de realizar este trabalho e aprender que é possível a interligação de várias linguagens mesmo sendo elas bastante distintas. Utilizando esta metodologia é possível fazer com que a linguagem de baixo nível, que geralmente é mais rápida, efectue as consultas, efectue os cálculos, ou seja, efectue todas as operações, para que estas sejam processadas mais rapidamente. Deixando assim para a linguagem de alto nível a apresentação dos mesmos. Para a realização deste trabalho foi também necessária a consulta da documentação referente às APIs utilizadas, SQLite/C e Python/C, o que foi uma mais-valia para a nossa formação. Quanto ao gprof, se soubesse que não iria funcionar com PyObjects teria desenvolvido todo o trabalho de maneira diferente, para que certas funções não ficassem dependentes de destes objectos, podendo assim efectuar uma compilação com o gprof. Bibliografia [1] Python/C API Reference Manual, < http://docs.python.org/c-api/>