Arquivo da categoria ‘Computação’

Twitter

24 Dezembro, 2009

Aí vai o link do meu twitter, que acabei de criar:

http://twitter.com/marcusaureliusf

Não sei se vou usar muito. Acho que vai servir mais pra responder as twitadas dos outros, já que o twitter não permite responder sem ter uma conta… (pelo menos não que eu saiba). Ainda acho que um blog com limite de caracteres não é uma grande invenção, hehe.

Jogos antigos

3 Dezembro, 2009

Bah, disseram que os jogos que eu jogo no computador são antigos! Pra mim, jogo antigo é de antes de 1989! Os do Mega Drive são “do meu tempo”. Depois de 2000 ou um pouco antes são todos jogos considerados novos :-) Bom, às vezes eu chamo os de Mega Drive de antigos também, embora não ache tanto.

Quero ver eu achar tempo pra jogar agora que não estou mais de férias. Tem uns jogos e umas demos aqui que eu nem encostei, e que eu esperava ter jogado nas férias. Gunbound, por exemplo.

Hitman

1 Dezembro, 2009

Inspirado pelos excelentes posts sobre videogames da Mariane (http://www.bitpop.info), resolvi postar sobre um dos jogos que fiquei jogando nas férias (nerd!). O jogo é Hitman: Contracts.

As fases dos jogos da série Hitman têm como objetivo matar uma pessoa da maneira mais silenciosa possível. Pois é, não é recomendado pra menores de 18 anos… É interessante porque difere da temática “atire em tudo que se mexe”. Sempre há várias maneiras de cumprir cada missão: envenenar a comida, estrangular, esfaquear, dar um tiro, plantar uma bomba, superaquecer uma sauna, sufocar com travesseiro, etc. E se ficar trancado sem saber o que fazer, sempre tem muitas FAQs disponíveis na internet.

O primeiro que eu joguei, uns anos atrás, foi Hitman 2: Silent Assassin. Muito bom jogo e com muitas fases (e fases interessantes!). Dá pra usar clorofórmio pra fazer uma pessoa dormir, para então se disfarçar com a roupa dela e poder entrar impunemente no lugar onde está a sua vítima. Nestas férias  joguei Hitman: Contracts (Hitman 3). Achei o jogo meio curto (ainda mais que eu li um guia para resolver a maioria das missões, daí sim passa rápido mesmo) mas também é muito bom. Além disso, ele usa uma seringa (com sei-lá-o-quê dentro) em vez de clorofórmio.

Um defeito de ambos é que numa fase os guardas são muito espertos e desconfiados (exemplo: se você está disfarçado de policial e corre perto de outros policiais eles começam a atirar em você), e noutra fase são muito burros e cegos (exemplo: não enxergam você cometer o crime a 5 metros de distância simplesmente porque estão olhando para outro lado). Várias vezes eu disse: “Mas essa missão é impossível!”, para então ler o guia que me dizia que eu podia estrangular  o alvo na frente de todo mundo, bastanto pra isso dar uma pequena distraída nos guardas fazendo-os olhar pra outro lado (eles vão ficar parados olhando pro outro lado eternamente). E pra saber se os guardas são burros ou inteligentes, só testando.

Então, depois de terminar o Contracts eu fui jogar o primeiro da série Hitman: Codename 47 (Hitman 1) e bah, me decepcionei. Os gráficos são muito ruins (por ser o jogo mais antigo), os comandos são muito desajeitados (dá pra configurar, mas não dá pra deixar igual aos outros), o mapa demora muito pra carregar (alternar entre a visão do jogo e do mapa é entediante), o mapa quase não dá informações e as letras da tela são muito, muito ruins de ler. Ainda estou decidindo se jogar esse jogo até o fim vai ser divertido ou vai ser irritante. Pra piorar, algumas fases do Contracts são fases do Hitman 1 refeitas (muito bem refeitas), o que tira ainda mais a graça do Hitman 1. Sou fã da série a partir do 2, hehehe. Falta jogar o Hitman: Blood Money (Hitman 4), pois dessa versão só joguei uma demonstração. Infelizmente, não conheço os outros jogos do gênero, então não vou poder comparar o Hitman com seus concorrentes.

E antes de terminar, tem uma coisa que eu acho bem estranha nesse jogo. Primeiro uma contextualização, se é que é necessária: o jogo é pra maiores de 18, mostra vários tipos de morte como eu já disse anteriormente, mostra uma garota seqüestrada e esquartejada na segunda fase do Contracts, festinhas com mulheres com roupas esquisitas (por “esquisitas”, entenda aquelas coisas de látex e tal) na mesma fase, drogas e mais de um shows de strip-tease (nunca total) em outras fases. Entretanto, se você entrar no banheiro de uma casa ou de um quarto do hotel, verá que no jogo os personagens tomam banho que nem no Big Brother: de roupa de banho!!! Quer dizer, o jogador pode ver todo o tipo de crueldade, mas uma mulher ou um homem pelado não pode? Putz. O negócio é tão ilógico que dá vontade de mandar um e-mail para a produtora do jogo mandando colocar mais uns pixels cor de pele e acabar com essa incoerência. Como disse um participante de um fórum (acho que era do gamefaqs.com): “Se eu tivesse um filho que imitasse tudo o que vê nos videogames, eu ia preferir que ele imitasse uma pessoa tomando banho pelada do que um assassino estrangulando suas vítimas”. Bom, pra dizer a verdade, no Hitman 2 tem um (só 1) cara pelado numa banheira com várias mulheres de biquíni. Como ele é meio gordo, a barriga tapa tudo, hahahaha.

Detalhes… (Windows 7)

29 Outubro, 2009

Alguém pode me explicar o que raios é esse espaço em branco (onde estão os pontos de interrogação) nesta janela?Janela "Opções de pasta" com espaço vazio desperdiçado à direitaQuando eu vi isso no Windows Vista achei estranho. Pensei que fossem corrigir no Windows 7. Mas está a mesma coisa! Será que corrigem no Windows 8?

Se não fosse esse espaço em branco, nem seria necessário ter uma barra de rolagem horizontal na lista “Configurações avançadas”…

Na versão em inglês não tem esse problema:

Versão em inglês das opções de pasta, sem espaço em branco.

Dia das crianças

11 Outubro, 2009

Na véspera do dia da criança, estou jogando Street Fighter IV! Muito massa! Pra quem ainda jogava jogos de 10 ou 15 anos atrás como eu, é deslumbrante o visual de um jogo atual! Aliás, alguém tem alguma dica de jogo pra eu botar em uso a minha placa de vídeo nova? :-)

Interpolação de strings em Python

8 Outubro, 2009

Mas que coisa! Em Python é só o cara passar um tempo fora e quando chega de volta já mudou um monte de coisas na linguagem. Quando eu aprendi a linguagem (na versão 2.3, há uns 5 anos), só havia uma maneira de inserir valores no meio de uma string: com o operador %, que funciona parecido com o printf do C.

Mas agora fui baixar o Python 3.1 pra automatizar uma tarefa aqui e me deparei com 3 (3!!!!! dá pra acreditar???) métodos totalmente diferentes de fazer a mesma coisa. O (1) jeito antigo do operador %, com a sintaxe “%d”, “%s”, “%f”, etc.; (2) a classe Template, com a sintaxe “${nome_campo}”, e (3) o método format, com a sintaxe “{nome_campo}”

Onde eles estavam com a cabeça? O Python 3 não era pra limpar a linguagem de coisas incoerentes? Por exemplo o caso do print, que era um comando especial e foi transformado em função. Li e reli os PEPs (0292 e 3101) e, embora eles tentem explicar, não entendi qual é o motivo de precisar de 3 formas diferentes de formatar strings, cada uma com uma sintaxe diferente. Não era o Python que dizia “There should be one– and preferably only one –obvious way to do it.”? (retirado do import this). Eu justamente preferia Python a Perl e Ruby porque estas duas têm milhares de maneiras de fazer as mesma coisas, com minúsculas diferenças (ex.: && e and) que fazem a gente perder tempo com minúcias.

Bom, fora isso, Python parece continuar sendo uma linguagem com uma legibilidade muito boa, poderosa e de alta produtividade. Se alguém tiver algo mais a comentar sobre a linguagem (especialmente da versão 3 em diante, que tem mais novidades), posta aí!

Classificação de músicas do Windows Media Player 11

8 Outubro, 2009

Por que será que o Windows Media Player 11 classifica com 4 estrelas (de um máximo de 5 estrelas) músicas que só tocaram uma vez? Nas versões anteriores não era assim. Só num computador que uso que o Media Player classifica músicas novas com 2 ou 3 estrelas. Nos outros ele já põe 4 estrelas quando só tocou uma vez. Não dá pra entender. É um saco. :-(

Linux é difícil

22 Novembro, 2008

Eu postei uma vez um texto no blog dando um exemplo de como o Linux pode ser fácil de usar. Agora vou dar o exemplo contrário, e expressar a minha indignação.

Trata-se de um fato acontecido no mesmo computador descrito no outro post. A distribuição que veio já foi trocada por um Mandriva há bastante tempo. É uma das distribuições famosas e com fama de fácil de usar. Certo dia eu estava lá em Santa Maria e me pediram pra instalar a impressora (multifuncional) nova. No Windows do notebook (esse notebook era meu, mas eu dei ele pra minha mãe), foi fácil, embora um pouco demorado. É só colocar o CD, seguir as instruções e conectar o cabo quando indicado.

Já no Linux… A primeira coisa que eu pensei foi: “Certo, dizem que a HP tem um bom suporte a suas impressoras no Linux. Não estou com muita paciência, mas acho que não vai ser difícil”. Primeiro tentei usar as ferrramentas da distribuição Mandriva. Tudo muito bonito e organizado, mas… não tinha o modelo de impressora na lista! Pronto, começou… Fui procurar na internet. Li relatos de que esse modelo tinha funcionado automagicamente no Ubuntu. Aí eu já comecei a ficar meio irritado pelos esforços desperdiçados na comunidade Linux. Algo que funciona tranqüilamente numa distribuição, causa um monte de irritações ao usuário da outra até o dia que os mantenedores dela resolverem/conseguirem adicionar o recurso correspondente. Recurso esse que já existe em outra distribuição. Mas não basta existir na outra, pois sempre tem uns detalhezinhos que devem ser ajustados, portados ou redesenvolvidos…

Então tá. Segunda opção: o saite da HP. Procurei um pouquinho e achei o lugar dos drivers, num saite separado do principal. Havia várias distribuições suportadas, inclusive o Mandriva que estávamos usando. Baixei e segui as instruções. No parágrafo anterior eu tinha tentado um instalador gráfico e bonito do painel de controle do Mandriva. Agora estava eu de frente com um instalador em modo texto, que pergunta no início da instalação se ele detectou corretamente a distribuição que estou usando. Argh.

Dava pra notar que o instalador tinha sido bem trabalhado pra funcionar em várias distribuições. De novo eu fiquei pensando no desperdício de esforços pra fazer isso. O instalador detectou a distribuição, tentou instalar pacotes, detectou que eu estava com o package manager aberto e pediu que eu o fechasse. Ótimo. Me instruiu a cadastrar os repositórios de pacotes. Ótimo. Só que bah, a essa altura eu já tinha dado vários comandos na linha de comando. Eu não conseguiria imaginar um usuário comum fazendo isso. O usuário talvez nem soubesse que deveria procurar os repositórios de pacotes 64 bits. No fim, o cadastro de repositórios foi demorado e completamente não-intuitivo. Se não fosse o instalador me indicar o saite com as informações, eu nunca teria paciência de descobrir como cadastrar os repositórios certos (eu estava em Santa Maria só no fim-de-semana, não queria perder muito tempo). E, pelo que me lembro, os repositórios que estavam cadastrados antes não eram os recomendados. Devia ser por isso que várias atualizações estavam falhando.

Mas mesmo seguindo todas as instruções, algumas dependências não puderam ser resolvidas. Aí que foi a parte estressante. Foi um baita trabalho pra instalar manualmente algumas coisas, desativar recursos que eu não consegui instalar e finalmente convencer o instalador que as dependências estavam realmente ali, já que o nome de certos pacotes não era igual ao esperado (acho que por causa do “64″ no nome). Depois de agüentar várias mensagens de erro nada descritivas, como “O pacote não pôde ser instalado”, imprimi a página de testes, e quase fugi correndo pra que não me pedissem pra testar o escâner, hehe.

Isso tudo que eu estava usando uma distribuição suportada pelo instalador da HP! Imaginem se fosse uma daquelas desconhecidas que costumam vir pré-instaladas nos computadores! A conclusão a que eu cheguei é que tudo é muito bonito e fácil usando os recursos e repositórios de pacotes da distribuição. Precisou instalar algo que não esteja no repositório oficial, caímos no modo texto e na instalação a partir dos códigos-fontes, pois desse jeito é mais fácil desenvolver algo que seja compatível com múltiplas distribuições. E mesmo assim, nesse desenvolvimento deve ter sido gasto um bom tempo pra lidar com as particularidades de cada distribuição. Foi aí que entendi perfeitamente por que o saite dizia que a instalação no Linux não tinha suporte por telefone. Imaginem a dificuldade do atentende tentando guiar um usuário comum pela instalação em sabe-se-lá-qual-distribuição…

Essa história de cada distribuição inventar seu instalador, seu gerenciador de pacotes e de drivers é muito desperdício de esforço. Esse é exatamente o mesmo tipo de problema que eu enfrentava há uns 6 anos atrás, quando usava Linux com mais freqüência. Enquanto certos programas de código livre são maduros e estáveis, sempre nos deparamos com aquele programinha mal feito, incompatível com o resto do mundo e totalmente desconhecido fora do círculo de usuários da distribuição, criado de qualquer jeito como um tapa-buraco pelos próprios desenvolvedores da tal distribuição. E a cada 6 meses, temos uma nova e maravilhosa versão, corrigindo os bugs da anterior e criando novos, andando em círculos. Quando a gente acha que se acostumou com as idiossincrasias de uma versão, muda tudo.

Já vi gente desistir do Linux porque o programa desejado só tinha pacotes pra Red Hat e Debian. Para as outras distribuições, as instruções eram: compile o código fonte! Inaceitável.

loop

26 Fevereiro, 2008

Enquanto eu escrevia o post anterior, ainda acabei fazendo um mini-teste paralelamente.  Estão vendo o loop abaixo?

sub ecx, 1;
test ecx, ecx;
jnz loop_label;

Pois então, existe uma instrução em assembly que faz exatamente o mesmo que essas 3 instruções. Ela se chama loop.

loop loop_label;

Ela decrementa ecx e repete o loop enquanto ecx não for zero. Experimentei usar essa instrução, e o interessante é que em todos os testes ela foi mais lenta do que usar as 3 instruções separadamente! Isso acontecia nos dois processadores (Pentium 4 e Sempron). Não coletei resultados, mas a instrução loop demorava consistentemente alguns poucos ciclos a mais. Por isso optei pela versão mais rápida, com 3 instruções. Não que isso fosse fazer diferença nos resultados do post anterior, mas é interessante, né?

static_cast<int>(double_var);

13 Fevereiro, 2008

Pois então, continuando o assunto do assembly do post anterior…

Segundo lia em vários lugares, truncar um double para um int é uma operação lenta na arquitetura x86, apesar de ser uma operação básica das linguagens C e C++. O interessante é que arredondar um número é mais rápido porque as flags do processador ficam por default no modo de arredondamento (depois de muito pesquisar, parece que esse default é pra obter mais precisão nas operações em geral, pois não é só a conversão pra int que faz uso dessa flag).

Então achei que esse seria um bom motivo pra aprender um pouco mais de assembly, já que o ganho de desempenho parecia ser significativo e alternativas usando construções de alto nível são esparsas: tem o lrint do C99, tem bibliotecas externas com uma função round, como o cvRound da OpenCV que usam assembly, mas nada suficientemente bom (você instalaria uma biblioteca só pra ter uma função round? é melhor copiar a função direto). E faria as medidas com outra instrução assembly, a rdtsc.

As funções que eu usei são as seguintes (se acharem algum erro, me avisem; assembly não é minha especialidade, hehe):

Pra obter o tempo atual:

/* O VC++ 2002 não aceita long long, vai __int64 mesmo... */
__declspec(naked) unsigned __int64 get_rdtsc()
{

__asm
{

push ebx;
xor eax, eax;
cpuid;
rdtsc;
pop ebx;
ret;

}

}

Pra fazer 400 conversões de double pra int em assembly, com fld seguido de fistp:

__declspec(naked)
unsigned __int64 asm_double_to_int(...)
{

__asm
{

/* Preferi fazer toda a manipulação da pilha à mão (por isso o __declspec(naked)) */
push ebp;
mov ebp, esp;
sub esp, 12;

call get_rdtsc;
mov dword ptr [ebp-8], eax;
mov dword ptr [ebp-4], edx;

mov ecx, 100; // Loop counter
loop_label:
fld qword ptr [ebp+8];
fistp dword ptr [ebp-12];

fld qword ptr [ebp+8];
fistp dword ptr [ebp-12];

fld qword ptr [ebp+8];
fistp dword ptr [ebp-12];

fld qword ptr [ebp+8];
fistp dword ptr [ebp-12];

sub ecx, 1;
test ecx, ecx;
jnz loop_label;

call get_rdtsc;

/*
A subtração de valores 64 bits eu tirei daqui:
win32-assembly-cheat-sheet
*/

sub eax, dword ptr [ebp-8];
sbb edx, dword ptr [ebp-4];

mov esp, ebp;
pop ebp;
ret;

}

}

Pra fazer 400 casts de double pra int em C++, com o mesmo tipo de loop feito:

/* Com as variáveis volatile o otimizador não remove código inútil... */
unsigned __int64 cast_double_to_int(volatile double a)
{

int i = 100;
unsigned __int64 t1 = get_rdtsc();
volatile int j;
do{

j = static_cast<int>(a);
j = static_cast<int>(a);
j = static_cast<int>(a);
j = static_cast<int>(a);

}while(--i);
unsigned __int64 t2 = get_rdtsc();
return t2 - t1;

}

O código do main está abaixo. Testo o arredondamento de 2 números (5.5 e 1.125) repetindo cada teste 8 vezes.

int main(int argc, char ** argv)
{

const int reps = 8;
unsigned __int64 tempo;
cout << "Assembly (default rounding):\nTest 1:\n";
for(int i = 0; i < reps; ++i){

tempo =
asm_double_to_int(5.5);
cout << tempo << '\n';

}
cout << "Test 2:\n";
for(int i = 0; i < reps; ++i){

tempo =
asm_double_to_int(1.125);
cout << tempo << '\n';

}
cout << "---------------------------------\nC++ cast (truncating):\nTest 1:\n";
for(int i = 0; i < reps; ++i){

tempo =
cast_double_to_int(5.5);
cout << tempo << '\n';

}
cout << "Test 2:\n";
for(int i = 0; i < reps; ++i){

tempo =
cast_double_to_int(1.125);
cout << tempo << '\n';

}
return 0;

}

Então vamos aos resultados. Fiz os testes no Visual C++ .NET 2002 e no Visual C++ .NET 2005 Express. Não testei com o GCC porque a sintaxe de inline assembly é meio esquisita e eu não aprendi direito. Testei em duas máquinas. Uma é um Intel Pentium 4 Northwood 2.4 GHz e o outro é um AMD Sempron Mobile 3000. Os resultados são em número de ciclos, não em segundos. Quanto mais ciclos, mais lento, mas só se a comparação for feita com outra execução no mesmo processador. A compilação é em modo Release (isto é, com otimizações).

VC++ 2002, Pentium 4 2.4GHz:


Assembly (default rounding):
Test 1:
2440
1540
1424
1424
1460
1424
1424
1460
Test 2:
1460
1460
1424
1424
1460
1424
1424
1424
---------------------------------
C++ cast (truncating):
Test 1:
26440
26236
25904
25904
26440
26440
25472
26440
Test 2:
26440
26452
25904
26440
25472
26808
25580
25904

========================

VC++ 2005, Pentium 4 2.4 GHz:


Assembly (default rounding):
Test 1:
2460
1412
1428
1412
1420
1412
1420
1420
Test 2:
1412
1420
1412
1424
1412
1412
1420
1412
---------------------------------
C++ cast (truncating):
Test 1:
8760
6896
6904
6900
6904
6904
7560
6892
Test 2:
6900
7248
6900
6904
6904
6904
6904
6904

========================
========================

VC++2002, Sempron Mobile 3000:


Assembly (default rounding):
Test 1:
992
877
877
877
877
877
877
877
Test 2:
877
877
877
877
877
877
877
877
---------------------------------
C++ cast (truncating):
Test 1:
8281
7366
7330
7294
7294
7294
7294
7294
Test 2:
7294
7294
7294
7294
7294
7294
7294
7294

========================

VC++2005, Sempron Mobile 3000:


Assembly (default rounding):
Test 1:
773
708
708
689
689
689
689
689
Test 2:
716
689
689
689
689
689
689
689
---------------------------------
C++ cast (truncating):
Test 1:
4902
4678
4678
4647
4922
4922
4922
4922
Test 2:
4695
4922
4922
4922
4922
4922
4922
4922

Conclusões:

1 – Dá pra ver que o Pentium 4 precisa de mais ciclos pra fazer a mesma coisa, por isso os Pentium 4 tinham freqüências maiores, pra compensar isso. (eu disse “tinham” porque a geração do Pentium 4 já passou, hehe)

2 – O VC++2002 executa o truncamento chamando uma função que arredonda e, se necessário faz uma subtração pra transformar o arredondamento em truncamento. O VC++2005 chama uma função que trunca usando uma instrução SSE2 (cvttsd2si) do processador, que é bem mais rápida, como dá pra ver. O programa decide dinamicamente se o SSE2 está disponível e usa a instrução em caso afirmativo. Nos testes, os 2 processadores tinham SSE2.

3 – Não importa qual seja a técnica usada pelo compilador, nem o processador, arredondar em assembly sempre resulta em menos instruções e maior desempenho do que truncar com um cast. Isso é interessante de ser feito quando você precisa de um int a partir de um double e não importa se vai truncar ou arredondar. Por exemplo, quando coordenadas em double precisam ser convertidas pra coordenadas de pixels, a diferença é minúscula, ainda mais se for uma animação. Outro caso é a linguagem Lua, que usa bastante a conversão de double pra int (pois todas as variáveis numéricas em Lua são double) e por isso usa este tipo de truque pra fazer a conversão, já que tanto truncar quanto arredondar servem.

Se você tem um loop interno fazendo muito dessas conversões de double pra int, convém considerar usar uma funçãozinha em assembly com fld e fistp como esta:

inline int double_to_int(double val)
{

int t;
__asm
{

fld val;
fistp t;

}
return t;

}

4 – Naturalmente, o assunto não está esgotado, pois existem muitos outros tipos de processador pra comparar, compiladores (que resultados será que o GCC e o compilador Intel gerariam?) e maneiras de truncar doubles, como por exemplo: fazer como o VC++2002 (com arredondamento e alguns testes); como VC++2005 (com SSE2); setando as flags do processador pra truncar (ruim porque exige esvaziar o pipeline, se os compiladores não geraram isso, deve ser lento, hehe); ou usar a instrução fisttp do SSE3 (sei que o meu Pentium 4 não a suporta; não tenho muita idéia do seu desempenho). Pra arredondar também deve haver mais algumas alternativas… Além de tudo isso poderia fazer experimentos setando as opções do compilador pra usar “fast math” e ver que código o compilador gera, mas daí eu não ia terminar nunca este post!!