sexta-feira, 9 de julho de 2010

Projetos no StackExchange

Pessoal, normalmente não goto de fazer esse tipo de coisa, mas para esses dois projetos eu fico feliz em fazer propaganda. Hoje, dando uma olhada nos projetos do Area51 do StackExchange, me deparei com dois que me chamaram atenção:
Pra quem não conhece, vale a pena dar uma lida sobre o StackExchange. Resumindo, é uma encubadora de sites de perguntas e respostas como o StackOverflow. Eles usam um sistema que investiga o interesse do público em relação à uma proposta de tópico para um novo site. Por isso, é importante a participação do público para que uma proposta possa de fato se tornar realidade.
Eu mesmo quase não estou participando desses projetos (nem de nenhum outro), devido à falta de tempo. Mas mesmo assim, tenho a cara-de-pau de pedir a participação nesses dois projetos para que os mesmos possam se tornar projetos definitivos.
Acredito que os dois serão de suma importância para a disseminação do conhecimento nas áreas de Inteligência Artificial[1] e da Ciência da Computação de forma geral (teoria).
Bom, feito o meu humilde pedido, vou ficar por aqui. Sei que não tenho postado com muita freqüência, mas vou tentar arrumar mais tempo pra fazer uns posts bem legais!!
Abraços!
[1] Embora eu ainda esteja usando o termo Inteligência Artificial por razões históricas, ultimamente eu tenho achado o termo Inteligência Computacional mais preciso. Embora muitos teóricos digam que Inteligência Artificial e Inteligência Computacional sejam ramos distintos de pesquisa, eu os considero o mesmo.

quinta-feira, 15 de outubro de 2009

Linguagens de Programação e Plataformas de Desenvolvimento

Bom…Nesse post vou falar sobre um ponto de vista que tenho sobre as linguagens de programação e plataformas de desenvolvimento. Estou usando uma nomenclatura que sinceramente não sei se é adequada. “Plataforma de desenvolvimento” pode ser entendido como várias coisas: um conjunto de programas utilizados para auxiliar na tarefa do desenvolvimento, a arquitetura destino de um determinado programa etc. Eu estou chamando de “Plataforma de desenvolvimento” uma plataforma intermediária que entenda uma linguagem intermediária entre as linguagens de alto nível e a linguagem de máquina (alguém disse “.NET”??).

Para dar continuidade ao post, vou recorrer a pre-história (é assim mesmo que se escreve??). No começo de tudo, os programadores não tinham opção de programar em alto nível. Eles tinham que fazer um rapel suicida até as entranhas dos uga-uga-computadores. O tempo passou, a modinha dos cartões perfurados passou, a mania supimpa de assembly passou e chegamos no estágio da programação alto-nível (viva o C!!). Nesse estágio, qualquer criança de 8 anos consegue escrever um programa razoável com um mínimo de conhecimento (tá bom, 9 anos). Porém, há algum tempo, o paradigma da programação em alto nível está mudando um pouco.

Nos primórdios da programação em alto nível, nós tínhamos algo do tipo (eu sei que removi alguns detalhes como a link-edição, mas eu não estou nem aí):

1 Porém, com o surgimento do Java, esse paradigma mudou um pouco para algo do tipo (de novo, deixei algumas coisas de lado - bye, bye JIT – e não estou nem aí):

2 Com essa nova camada (a Plataforma Intermediária – Virtual Machine para os íntimos) o mesmo programa pode rodar em diversas plataformas sem necessidade de recompilação (por que seu código gerado é em uma linguagem intermediária). Eu acredito que o povo da Sun bolou esse novo paradigma para que não houvesse a necessidade de recompilação do código para que ele rodasse em diversas plataformas distintas.

Mais tarde, a gang do tio Bill desenvolveu a plataforma .NET. Ao contrário do Java, o código .NET não tem pretensão de rodar em sistemas que não sejam Windows. O grande chamariz do .NET é a independência da linguagem de alto nível em relação ao código gerado. Ou seja, um programador pode escrever parte do programa em C-Jogo-Da-Velha e outro “programador” pode escrever parte do código em Visual Basic (uurgghhh).

Agora chega o meu ponto de vista…O futuro é unir o melhor dos dois mundos: Java e .NET. Com uma plataforma intermediária que rodasse em diversas plataformas diferentes e com independência da linguagem de alto nível a ser utilizada. Um espertinho qualquer que queira me sacanear pode muito bem falar que isso já existe. Concordo. Um belo exemplo é a utilização da linguagem Groovy para gerar bytecodes que rodam na plataforma Java. Porém, o compilador do Groovy é feito a parte da plataforma Java. Acho que as plataformas intermediárias deveriam ter capacidade de geração de “plug-ins” para reconhecimento de diferentes linguagens e deveriam ter um compilador genérico para compilar qualquer linguagem na sua linguagem intermediária. Possivelmente, esses plug-ins deveriam conter a sintaxe e a semântica da linguagem a ser reconhecida (nada fora do normal pra quem está acostumado com criação de compiladores e interpretadores).

Tendo exposto esse ponto de vista meu, sou obrigado a dar uma outra percepção que tenho de acordo com minhas experiências e minhas leituras na rede mundial de computadores. O JAVA ESTÁ MORTO (OU ESTARÁ EM POUCO TEMPO)!!!! Muita calma nessa hora!! Vou mudar a minha frase. A LINGUAGEM JAVA ESTÁ MORTA (OU ESTARÁ EM POUCO TEMPO)!!! Ao meu ver, a plataforma Java ainda tem um futuro brilhante a frente. Porém, a linguagem Java está fadada a um término decadente e decepcionante. É uma linguagem muito verbosa, na qual se escreve de mais. É uma linguagem que não traz a praticidade de outras linguagens (viva Groovy!!). É uma linguagem que não é flexível como outras (viva Groovy!!). Em fim…A linguagem Java não acompanhou o desenvolvimento como outras fizeram. Cito: Groovy (lógico), Scala e Ruby. Na minha opinião, essas três estão entre as mais avançadas linguagens de programação da atualidade.

Não posso terminar esse post sem deixar outro ponto de vista meu. .NET NÃO RODA EM LINUX!! O povo do Mono que me perdoe, mas é muito fácil de achar programas escritos em .NET (ou seja, compilados para a CLR) que não funcionam em Mono. Um outro fator importante para essa afirmação minha é a defasagem entre versões .NET e Mono. Não sei como anda o Mono agora, mas até pouco tempo o Mono era “compatível” somente com o .NET 2.0, quando o mesmo já estava na 3.5. Embora seja mais raro, o contrário também ocorre. Há programas escritos em Mono que não rodam no .NET. Um deles é o Banshee (player muito bom feito para Linux).

Vou parar por aqui. Sei que a minha utopia é muito utópica mas eu gostaria mesmo de ver uma grande plataforma intermediária a la .NET e Java, com independência de sistema-alvo e de linguagem de alto nível utilizada. Quem sabe eu ainda tenha tempo para escrevê-la…

[]s

terça-feira, 1 de setembro de 2009

Integração entre Lumis Portal e a linguagem de programação Groovy

Depois de muito tempo sem postar, decidi falar um pouco sobre um pequeno teste que estou realizando. Esse teste, a pesar de ser muito pequeno e limitado, é muito válido no que diz respeito ao gerenciamento e manutenção de um portal. Embora eu esteja falando especificamente do Lumis Portal, acho que a mesma abordagem pode ser feita em outros produtos.
Esse post refere-se mais ou menos ao meu outro post Interpretadores Incorporados.
Bom, para começar, vou usar um pequeno exemplo mega-fictício de uma situação em que desejássemos criar 100 páginas no nosso portal. Obviamente, essa situação é totalmente irreal (ou não!). Esse tipo de operação é muito difícil, devido à sua escala.
Inicialmente, nosso portal estaria com a seguinte configuração:
lumgroovy-1 No teste que eu estou trabalhando, existe uma pequena interface como na figura a seguir:
lumgroovy-2 Pausa para reflexão………Sim! Eu também estou fazendo testes com o JRuby!!!
Continuando…
Nessa interface existe uma combo para seleção da linguagem do script, uma Text Area para digitação do script e um botão de executar (adivinhe…para executar o script!). Agora imagine que nessa caixa de texto, eu digite algo como:

import lumis.portal.manager.ManagerFactory
import lumis.portal.channel.ChannelConfig
import lumis.portal.authentication.SessionConfig
import lumis.portal.transaction.PortalTransactionFactory
import lumis.portal.page.PageConfig

def pm = ManagerFactory.getPageManager()
def pci = ChannelConfig.PORTAL_CHANNEL_ID
def sc = SessionConfig.getCurrentSessionConfig()
def tr = PortalTransactionFactory.getCurrentTransaction()

0.upto(99){ i ->
def pc = new PageConfig()
pc.setChannelId pci
pc.setName "Página criada por script " + (i < 10 ? "0" + i : i)
pm.add sc, pc, tr
}

Então, após a execução desse script, nosso portal ficaria com essa aparência:
lumgroovy-3
E…Bingo!!! Lá estão nossas 100 páginas novinhas em folha (ok, não estão aparecendo todas, mas eu juro que elas estão lá!)!!!
Nesse teste, eu fiz o input através de uma interface e um Process Action Handler, contudo, nada impede que esse input seja feito através de um JSP ou uma console rodando no servidor, por exemplo.
Da mesma forma, do mesmo jeito que eu criei 100 páginas com um scriptzinho bobão, outras tarefas de manutenção e gerenciamento poderiam ser executadas.
Como um teste inicial, estou bem satisfeito com o resultado. Acho que ferramentas como o Lumis Portal deveriam oferecer um mecanismo desses já incorporados.
Vou ficar por aqui!
[]s!

segunda-feira, 25 de maio de 2009

Análise de possíveis memory leaks em programas Java (parte 2)

Continuando o último post, vou citar um método para identificar possíveis memory leaks em Java. Para isso, iremos fazer um dump da heap. Esse dump pode ser criado manualmente com o jmap ou automaticamente através de opções da JVM.

Primeiramente, vou mostrar como fazemos um heap dump de um programa que está rodando manualmente com o jmap. Para tal, precisamos saber o id do processo que está rodando (o jmap também tem opção de fazer heap dumps de processos remotos, mas não vou entrar nesse mérito). Uma vez conhecendo o id do processo, iremos rodar o programa

jmap –dump:file=heap.bin <pid>

Nesse caso, heap.bin é o arquivo com o heap dump que será gerado e <pid> é o id do processo.

Uma forma mais legal de se fazer heap dumps é quando o processo pára devido a um OutOfMemoryError. Para isso, precisamos informar à JVM que queremos que ela gere um heap dump automaticamente quando um erro desses ocorrer. Esse processo é bem simples. Basta chamar a JVM com as opções como a seguir:

java -XX:HeapDumpPath="./heap.bin" -XX:+HeapDumpOnOutOfMemoryError memoryleak.MemoryleakSimulator

A opção –XX:HeapDumpPath=”meuDump.bin” indica o nome do arquivo contendo o heap dump quando um OutOfMemoryError for lançado e a opção –XX:+HeapDumpOnOutOfMemoryError indica que a JVM deve criar um heap dump automaticamente.

Uma vez com o heap dump criado, vamos analisá-lo com o MAT. O MAT pode ser incluído em uma instalação pré-existente do Eclipse como um plug-in ou como uma instalação stand-alone (que eu prefiro). Assim que iniciamos o MAT e abrimos o arquivo, ele abre o seguinte wizard (que não é o curso de inglês!!):

image

Como estamos em busca de um possível memory leak, sugiro deixá-lo criar um Leak Suspects Report.

image

O gráfico representado pode variar bastante (nesse exemplo, ele é bem uniforme mas isso quase não acontece em aplicações reais). Um ponto que considero importantíssimo é a dominator tree. Para abrí-la, basta clicar no botão indicado da barra de ferramentas:

image

Uma vez aberta, a dominator tree aparecerá como a seguir:

image

Nesse exemplo é muito fácil identificar o memory leak, pois logo vemos que a maior porção retida da heap é dada a um vetor com mais de 2 milhões de objetos (a  contagem aparece no quadro inferior esquerdo). Claramente essa é uma situação de memory leak. Essa análise pode ser muito complicada e nem sempre é possível extrair dados conclusivos. O MAT possui inúmeros recursos que não vou citar devido a falta de tempo.

Esse post foi mais um norteador para que uma pessoa consiga realizar uma análise razoável, porém, uma análise realmente boa só é feita conforme o profissional adquire experiência.

Vou parar por aqui.

Até a próxima!!

[]s

quinta-feira, 7 de maio de 2009

Análise de possíveis memory leaks em programas Java (parte 1)

Neste post vou falar um pouco sobre como realizar uma análise inicial de possíveis memory leaks.

Para essa análise inicial, recomendo utilizar:

Essa análise baseia-se muito na máquina virtual da SunTM.

Para fim de testes, utilizarei o seguinte programa que simula uma situação de memory leak:

package memoryleak;

import java.io.IOException;
import java.util.Vector;

public class MemoryleakSimulator {
    private static final Vector<Double> memoryleak = new Vector<Double>();
    private static final double inc = Double.MIN_NORMAL;
    public static void main(String[] args) throws IOException
    {
        System.out.println("Pressione uma tecla para continurar...");
        System.in.read();
        System.out.println("Realizando memory leak...");
        Double d = new Double(0.0);
        while(true)
            memoryleak.add(d = new Double(d.doubleValue() + inc));
    }
}

Esse programa simula uma situação de memory leak. Ele adiciona objetos ao vetor memoryleak que jamais serão utilizados e, portanto, poderiam ser removidos .

Se simplesmente chamássemos o programa com

java memoryleak.MemoryleakSimulator

O programa cria um memory leak e é abortado com um java.lang.OutOfMemoryError.

Quando um erro desses ocorre, podemos desconfiar de duas coisas:

  1. A quantidade de memória da VM não está adequada às necessidades de uso de memória do programa; ou
  2. Existe um memory leak nesse programa.

Nesse post não vou considerar a 1a opção.

Para nos auxiliar na análise, coloquei um ponto de parada no programa, onde se deve pressionar Enter para continuar.

Para iniciar uma análise inicial, recomendo o monitoramento em tempo real da VM. Para tal, inicie o programa com

java memoryleak.MemoryleakSimulator

Quando o programa pedir para pressionar uma tecla, inicie o VisualVM. Quando feito, no painel do lado esquerdo aparecerá uma entrada do processo do programa que está sendo executado, como a figura a seguir:

analiseML Dando um duplo-clique no processo, abre-se no painel da direita uma série de abas contendo informações sobre a VM e sobre o processo sendo executado.

analiseML-2

Nessa primeira aba, apresenta-se informações sobre a virtual machine, incluindo parâmetros de inicialização, propriedades do sistema, argumentos passados, id do processo etc.

analiseML-3

Na segunda aba, exibe-se o uptime desse processo, um histograma da heap, um histograma da permgen, um histograma do número de classes carregadas e um histograma do número de threads. Vou voltar a falar mais sobre essa aba mais tarde.

analiseML-4

A terceira aba exibe informações sobre as threads correntes e passadas. Um duplo-clique na thread leva aos detalhes dela.

image

A quarta aba é uma aba para profile. Não vou citar essa aba mais nesse post.

image

A quinta aba é adicionada pelo plugin Visual GC. Essa aba exibe informações detalhadas do uso de memória da  VM (dividido nos diversos espaços de memória da VM).

Bom, para podermos analisar alguma coisa, pressione Enter para que o Memory Leak seja feito. Quando o programa termina, os gráficos no Visual VM serão mantidos (o que é uma boa idéia dos desenvolvedores!!) e assim podemos analisar o uso de memória. A escala dos gráficos dependerá do tempo levado para pressionar Enter para o programa continuar.

image

Esse programa que escrevi leva a uma situação de memory leak muito rapidamente, então a curva de utilização da heap cresce rapidamente. Porém, em aplicações reais, esse crescimento pode ser muito sutil, às vezes sutil o suficiente para que o memory leak não seja percebido.

image

Na aba do Visual GC, podemos ver que, a pesar do GC ter sido realizado algumas vezes, o uso da heap não diminuiu até o programa terminar.

Ok, mas o que isso que dizer??

NADA!!!!!

Significa apenas que o espaço da heap foi estourado (seja por uma situação de memory leak ou não). Se nós não soubéssemos previamente que esse programa cria um memory leak, não saberíamos que esse estouro da heap é causado por um memory leak.

Vou parar por aqui.

Continuo nesse assunto no próximo post!!!

[]s

quinta-feira, 9 de abril de 2009

Característica do member/2 no SWI Prolog

Nos últimos dias me deparei com uma característica um tanto chata na regra member/2.

Basicamente, o que ocorre é que quando se faz uma pergunta como ?- member(X, Y). e X está instanciado com um valor qualquer e Y não está instanciado o Prolog entra em loop infinito. Isso pode ser muito ruim dependendo da lógica do programa que está sendo escrito. Quando isso ocorre, duas coisas podem ser feitas:

Alterar a lógica do programa para impedir que essa situação ocorra.
Utilizar uma regra personalizada que retorne, por exemplo, falso em uma sicuação dessas.
Nos últimos dias parti para a segunda abordagem. Embora minha lógica não tenha funcionado, minha regra personalizada funcionou exatamente como esperado.

Eu simplesmente alterei de:

member(X, [X|_]) :- !.
member(X, [_|Y]) :- member(X, Y).

Para:

member(_, Y) :- var(Y), !, fail.
member(X, [X|_]) :- !.
member(X, [_|Y]) :- member(X, Y).

A primeira regra testa se Y está instanciada e, caso não esteja, retorna falso.

Com essa nova regra, caso uma pergunta como ?- member(1, X). seja feita e X não esteja instanciada, o Prolog responderá com falso.

[]s e até a próxima!!

Análise de performance de aplicações WEB (parte 5)

Continuando no assunto de análise de performance de aplicações web, vou falar um pouco sobre o teste de recuperabilidade. Este é um dos mais simples testes a serem realizados. Porém, nem sempre é simples de se obter resultados dele. Esse teste consiste em bombardear o servidor (ou o cluster) com o máximo de requisições possíveis durante o tempo que for necessário para que ocorra algum erro no servidor (ou no cluster ou no banco de dados etc.). É necessário esse bombardeamento para verificar se após um evento inesperado como esse a aplicação consegue voltar a responder normalmente.

Resumindo a ópera: bombardeie o servidor até ele começar a responder erro, páre de gerar requisições e veja se o servidor volta a responder normalmente.
Bem simples, né…

NÃO!!

Imaginem a seguinte arquitetura de infra:

Exemplo de infra

Dependendo do número de servidores e do porte dos servidores de cada cluster, o número de requisições necessárias para que a nuvem comece a responder com erros (dependendo do servidor de aplicações que esteja sendo utilizado, normalmente quando um número grande de requisições chega e ele não consegue atender a todas o AS responde com erro HTTP 5xx) pode ser muito grande. Às vezes, esse número se torna grande o suficiente para tornar o teste inviável.
Ou seja, embora esse teste seja muito simples de se realizar, nem sempre é possível coletar resultados conclusivos.
Uma questão que ainda não estou convencido sobre esse tipo de teste é se ele necessita ou não ser executado em ambiente de produção (ou em um ambiente com as mesmas características deste).
Poucas pessoas costumam aplicar esse tipo de teste.

Vou ficar por aqui!

[]s