Skip to content

Commit

Permalink
Merge branch 'master' into pe-missing-content
Browse files Browse the repository at this point in the history
  • Loading branch information
diogotcorreia authored Nov 13, 2023
2 parents 8c1729b + ccf9156 commit c22958f
Show file tree
Hide file tree
Showing 7 changed files with 653 additions and 67 deletions.
352 changes: 352 additions & 0 deletions content/al/0004-espacos-vetoriais.md

Large diffs are not rendered by default.

62 changes: 62 additions & 0 deletions content/al/0005-bases.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
---
title: Bases de um Espaço Vetorial
description: >-
Base de um espaço vetorial.
Coordenadas de um vetor numa base.
Dimensão de um espaço vetorial.
Matriz de Mudança de Base.
path: /al/bases
type: content
---

# Bases de um Espaço Vetorial

```toc
```

Podemos generalizar o referido no final da última página para espaços vetoriais, definindo o seguinte:

:::info[Definição]

Considerando um espaço vetorial $V$ sobre $\mathbb{K}$, um conjunto $\mathcal{B} = \{v_1, v_2, \cdots, v_n\} \subset V$
diz-se uma [**base**](color:orange) de $V$ se e só se $\mathcal{B}$ é linearmente independente e
gerador de $V$: $L(\mathcal{B}) = V$, portanto.

Os conjuntos geradores de espaços como $\mathbb{R}^m$ e $\mathbb{M}_{m \times n}(\mathbb{R})$
são, claro, as respetivas [**bases canónicas**](color:blue): no caso de $\mathbb{R}^m$, por
exemplo, temos $\mathcal{B} = \{e_1, e_2, \cdots, e_m\}$, onde $e_i$ é o vetor unitário
na direção $i$.

:::

## Coordenadas de um Vetor numa Base

Considerando um espaço vetorial $V$ sobre $\mathbb{K}$ e um conjunto $\mathcal{B} = \{v_1, v_2, \cdots, v_n\} \subset V$
tal que $L(\mathcal{B}) = V$, existirá um conjunto de escalares $\{c_1, c_2, \cdots, c_n\} \subset \mathbb{K}$
onde, $\forall u \in V$, existe necessariamente um vetor $v' \in \mathbb{K}^n$ (**único**) em que:

$$
v' = (c_1, c_2, \cdots, c_n), \quad u = c_1 v_1 + c_2 v_2 + \cdots + c_n v_n = \sum_{i=1}^n v'_i v_i
$$

No fundo, significa que podemos representar qualquer vetor $u \in V$ como uma combinação linear
de vetores da base $\mathcal{B}$ - fisicamente, estamos a transformar a representação de um vetor
em coordenadas cartesianas para outro sistema de coordenadas, neste caso, o sistema de coordenadas
definido pelos vetores da base $\mathcal{B}$.

Dizemos que estes escalares, correspondentes a $v'$, correspondem às [**coordenadas**](color:blue) de $u$ na base $\mathcal{B}$,
representando a posição de $u$ no espaço vetorial $V$. Podemos representar esta informação
da seguinte forma:

$$
(u)_{\mathcal{B}} = (c_1, c_2, \cdots, c_n) \in \mathbb{K}^n
$$

Note-se que a correspondência $u \mapsto (u)_{\mathcal{B}}$, $V \mapsto \mathbb{K}^n$,
é uma transformação que preserva a adição e a multiplicação por escalares:

$$
(u + v)_{\mathcal{B}} = (u)_{\mathcal{B}} + (v)_{\mathcal{B}} \quad \forall u, v \in V \\
(\lambda u)_{\mathcal{B}} = \lambda (u)_{\mathcal{B}} \quad \forall u \in V, \lambda \in \mathbb{K}
$$
136 changes: 136 additions & 0 deletions content/es/0002-unit-tests.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
---
title: Testes e Testes de Unidade
description: >-
Testes.
Testes de Unidade (Unit Tests).
White Box e Black Box testing strategies.
Partition testing.
Test doubles.
path: /es/unit-tests
type: content
---

# Testes e Testes de Unidade

```toc
```

Os testes automáticos permitem-nos ter confiança de que o nosso código funciona
e que não sofreu regressões (i.e. algo que funcionava deixou de funcionar) devido
a alterações não relacionadas.
No entanto, é importante ter em conta que ter todos os testes a passar
**não significa que o programa está livre de _bugs_**.

## Fases de Testagem

Existem 3 grandes fases onde os sistemas são testados:

- [**_Development Testing_**](color:green): o sistema é testado pelos **_developers_**
durante o desenvolvimento. Pode tomar a forma de _unit testing_, _component testing_
ou _system testing_.
- [**_Release testing_**](color:yellow): antes de uma nova versão do sistema ser
lançada e disponibilizada aos utilizadores, os **_QA Engineers_**, uma equipa
separada da equipa de desenvolvimento, testam todo o sistema.
- [**_User testing_**](color:red): os **utilizadores** do sistema testam o sistema,
por exemplo, através de uma versão _beta_ ou _alpha_ lançada antes da versão final.

## Estratégias de Testagem

- [**_Black box testing_**](color:pink): os testes são feitos a partir de uma **especificação**,
isto é, a descrição que levou à implementação.
- [**_White box testing_**](color:blue): os testes são feitos contra uma **implementação** específica.

:::info[Exemplo]

Imaginemos que temos uma estrutura do tipo FIFO implementada e queremos
testar o método `fifo.push()`.

No caso de não conhecermos a implementação (caso [_black box_](color:pink)), o óbvio
seria testar o caso em que a fifo está vazia, e o caso em que não está.

No entanto, se soubermos que a estrutura utiliza arrays de 512 elementos na
sua implementação, podemos (e devemos) também testar o caso em que é adicionado
um elemento a uma FIFO com 512 elementos (caso [_white box_](color:blue)).

:::

## Testagem de Partições

Quando estamos a testar um sistema, existem vários inputs (e os respetivos outputs)
que se comportam de forma semelhante.
Podemos, então, agrupar estes inputs quando escrevemos testes, numa técnica chamada
**Testagem de Partições** (ou, em inglês, [_equivalence partitioning testing_](https://en.wikipedia.org/wiki/Equivalence_partitioning)).

:::tip[Partition Testing]

Consiste em encontrar grupos de inputs (que não se intercetam) que se espera
que tenham um mesmo comportamento.
De seguida, cria-se testes para cada um destes grupos.

:::

Uma técnica usada em conjunto com a testagem de partições é a
análise de valores fronteira ([_boundary-value analysis_](https://en.wikipedia.org/wiki/Boundary-value_analysis)),
isto é, os valores que delimitam as várias partições.

:::info[Exemplo]

Vamos imaginar uma função `passOrFail(int grade)` que retorna `"pass"` se a nota
for entre 10 e 20 (inclusive), `"fail"` se a nota for entre 0 e 9 (inclusive) e
lança uma exceção para qualquer outro valor.

Seguindo a testagem de partições, vamos dividir o nosso espaço em 4 diferentes partições.

```
... -1 | 0 ... 9 | 10 ... 20 | 21 ...
-------------------------------------------
exception | fail | pass | exception
```

Considerando apenas a testagem de partições, temos de testar um valor
de cada uma das partições, por exemplo, -2, 4, 15 e 22.

No entanto, geralmente queremos também efetuar _boundary-value analysis_, pelo que
queremos incluir nos nossos testes os valores fronteira, -1, 0, 9, 10, 20 e 21.

Assim, se seguirmos ambos os métodos, os nossos testes deverão abranger 10 valores
diferentes e 4 partições.

:::

## Testes Unitários

Os Testes Unitários (_Unit Tests_) servem para testar os vários componentes
individualmente, isolados do resto do sistema.

As várias **unidades** podem ser:

- Funções ou métodos de um objeto
- Classes de objetos com vários atributos e métodos
- Componentes compostos (_composite components_) com interfaces bem definidas
que permitem aceder à sua funcionalidade.

Para termos _coverage_ total de uma classe, temos de:

- Testar todas as operações associadas a um objeto;
- Fazer _set_ e _get_ de todos os atributos do objeto;
- Utilizar o objeto em todos os seus estados possíveis.

## Test Doubles

Os _test doubles_ são objetos falsos que são usados no lugar de objetos verdadeiros
em testes.
Estes podem ser:

<!-- TODO explicar cada um deles -->

- Dummy objects
- Fake objects
- Stubs
- Spies
- Mocks

Estes têm a vantagem de isolar os testes a uma única unidade, de diminuir
as dependências ao efetuar testes e também simular casos difíceis de gerar.
50 changes: 50 additions & 0 deletions content/es/0003-code-coverage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
---
title: Code Coverage
description: >-
Code Coverage: statement, branch, condition e path coverage.
path: /es/code-coverage
type: content
---

# Code Coverage

```toc
```

Em _white-box testing_, podemos definir uma métrica que nos indica a percentagem
do nosso código que é testado, chamada de _code coverage_.

No entanto, existem diversos critérios que podemos aplicar, cada um com as suas
vantagens e desvantagens:

- [**_Statement Coverage_**](color:green)
- [**_Branch Coverage_**](color:orange)
- [**_Condition Coverage_**](color:yellow)
- [**_Path Coverage_**](color:blue)

## Statement Coverage

:::warning[Secção Incompleta]
Esta secção encontra-se incompleta. Procuram-se contribuidores.
:::

## Branch Coverage

:::warning[Secção Incompleta]
Esta secção encontra-se incompleta. Procuram-se contribuidores.
:::

## Condition Coverage

:::warning[Secção Incompleta]
Esta secção encontra-se incompleta. Procuram-se contribuidores.
:::

## Path Coverage

:::warning[Secção Incompleta]
Esta secção encontra-se incompleta. Procuram-se contribuidores.
:::

<!-- https://sqa.stackexchange.com/questions/20226/how-do-we-calculate-statement-coverage-branch-coverage-path-coverage-and-cond -->
40 changes: 24 additions & 16 deletions content/oc/0004-memoria-caches.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,10 @@ pequena de espaço de memória a qualquer momento durante a execução.
| mais caro | mais barato |
| estático, o conteúdo fica para "sempre" enquanto estiver ligado | dinâmico, precisa de ser "refrescado" regularmente (a cada 8 ms); consome 1% a 2% dos ciclos ativos da DRAM |

Para além disso, os endereços da DRAM são [divídido em 2 metades](color:pink), linha e coluna:
Para além disso, os endereços da DRAM são [dividido em 2 metades](color:pink), linha e coluna:

- [RAS (_Row Access Strobe_)](color:orange) que aciona o decodificador de linha;
- [CAS (_Columm Access Strobe_)](color:green) que aciona o selecionador de coluna.
- [CAS (_Column Access Strobe_)](color:green) que aciona o selecionador de coluna.

### Como Funciona a Hierarquia de Memória?

Expand Down Expand Up @@ -130,7 +130,7 @@ Se tentarmos aceder a dados e estes estiverem disponíveis no nível mais alto d
temos um [**_hit_**](color:green), caso contrário teremos um [**_miss_**](color:red)
e teremos de ir buscar os dados a um nível inferior.

Podemos ainda calcular o [**_hit rate_**](color:purple) de multiplos acessos através da seguinte fórmula:
Podemos ainda calcular o [**_hit rate_**](color:purple) de múltiplos acessos através da seguinte fórmula:

$$
\op{\text{Hit Rate}}
Expand Down Expand Up @@ -305,6 +305,14 @@ Existem três tipos de [cache misses](color:pink):
são mapeados para o mesmo set ou _block frame_, num set de associatividade ou até mesmo
em posicionamento de blocos em mapeamento direto.

### Cache Design Trade-offs

| Alteração | Efeito na _miss rate_ | Efeito negativo de _performance_ |
| :---------------------------------- | :-------------------------------- | :---------------------------------------------------------------------------------------- |
| Aumento do tamanho da cache | Diminuição de _capacity misses_ | Aumento do tempo de acesso |
| Aumento da associatividade da cache | Diminuição de _conflict misses_ | Aumento do tempo de acesso |
| Aumento do _block size_ | Diminuição de _compulsory misses_ | Aumento do _miss penalty_. Para blocos muito grandes, pode aumentar também a _miss rate_. |

## _Write-Policies_

Uma [_write policy_ da cache](color:pink) refere-se a um comportamento da cache
Expand All @@ -316,7 +324,7 @@ policies_.
### _Write-through_

Quando nos deparamos com um _data-write hit_ podemos somente atualizar o bloco da
cache, mas isto implicaria que a cache e a memória se tornassem insconsistentes. Temos,
cache, mas isto implicaria que a cache e a memória se tornassem inconsistentes. Temos,
por isso, que introduzir a política [_write-through_](color:pink): esta, sendo a mais
fácil de implementar, basicamente atualiza os dados tanto em cache como em memória ao
mesmo tempo. É usada quando não há escritas muito frequentes na cache e ajuda com a
Expand Down Expand Up @@ -377,7 +385,7 @@ diferentes:
## Medir a Performance da Cache

Para conseguirmos perceber se uma cache está a funcionar bem ou não, temos que saber
os termos involvidos nestes cálculos:
os termos envolvidos nestes cálculos:

- [Bloco ou linha](color:yellow): a unidade mínima de informação que está presente, ou
não, na cache;
Expand All @@ -393,7 +401,7 @@ os termos involvidos nestes cálculos:

Assim, como já sabíamos, os componentes do tempo do CPU são os [ciclos de execução do programa](color:purple),
que includem o tempo de _cache-hit_ e os [ciclos de atraso de memória](color:purple)
que provêm maioritariamente de _cache misses_. Assumindo que o sucesso de cache incui a
que provêm maioritariamente de _cache misses_. Assumindo que o sucesso de cache inclui a
parte normal dos ciclos de execução do programa, então podemos calcular o tempo de CPU
através da seguinte fórmula:

Expand Down Expand Up @@ -431,7 +439,7 @@ como um _miss penalty_ de 100 ciclos, uma [base CPI](color:yellow), ou seja, cac
ideal, igual a 2, e [loads e stores](color:purple) que ocupam 36% das instruções.

A primeira coisa que pretendemos calcular são os _miss cycles_ por instrução, que, como
vimos aicma, são dados pelo _miss rate_ e o _miss penalty_. Temos, por isso:
vimos acima, são dados pelo _miss rate_ e o _miss penalty_. Temos, por isso:

$$
\text{miss cycle} = \text{miss rate} \times \text{miss penalty}
Expand All @@ -456,11 +464,11 @@ Por isso. o CPU ideal é $$5.44/2=2.72$$ vezes mais rápido

### Ideias a Reter

Desta forma, concluimos que quando a performance do CPU aumenta, o _miss penalty_
Desta forma, concluímos que quando a performance do CPU aumenta, o _miss penalty_
[diminui](color:purple); uma diminuição baseada no CPI implica uma maior [proporção de tempo](color:purple)
gasto em atrasos na memória; e, um aumento de _clock rate_ significa que os atrasos de
memória contam para mais [ciclos de CPU](color:purple). Não podemos, evidentemente
negligenciar o comportamneto da cache quando estamos a avaliar a perfomance do sistema.
negligenciar o comportamento da cache quando estamos a avaliar a performance do sistema.

## Reduzir os _Miss Rates_ na Cache

Expand All @@ -472,7 +480,7 @@ um bloco de memória seja mapeado para qualquer bloco de cache numa [cache total

Por isso mesmo, o compromisso é dividir a cache em **sets** que contêm _n_ formas
([_n-way set associative_](color:pink)). Os blocos de memória mapeiam um _set_ único,
específicado pelo campo de index, e pode ser posto em qualquer sítio desse _set_, é por
especificado pelo campo de index, e pode ser posto em qualquer sítio desse _set_, é por
isso que há _n_ escolhas.

| [Totalmente associativo](color:yellow) | [Associatividade com _n_ sets](color:orange) |
Expand All @@ -494,19 +502,19 @@ encontra presente. Como não se encontra, temos um _miss_ e escrevemos na primei
o valor 0. Já tendo o 0 em cache, seguimos para o 4, vamos à primeira linha e vemos se
está na cache, contudo na cache só está o 0, logo, há um miss. Como estamos a tratar do
número 4, contamos as linhas até chegarmos à linha 4, como só há 4 linhas no total e
começamos a contar do zero, temos que modficar a nossa primeira linha para passar a ter
começamos a contar do zero, temos que modificar a nossa primeira linha para passar a ter
a informação relevante ao 0 para ter informação relevante ao 4. Assim, na nossa
primeira linha agora temos o 4.

Acabando os dois primeiros valores, passamos ao 0, vamos à primeira linha, vemos que já
está preenchida, há _miss_ e temos que voltar a preencher com o 0. Reparamos, por isso,
que temos o mesmo caso que no início do nosso exercício. Ora, como o resto dos valores
são sempre ou 0 ou 4 intrecalando, vamos sempre ter um _miss_ e vamos sempre ter que
são sempre ou 0 ou 4 intercalando, vamos sempre ter um _miss_ e vamos sempre ter que
voltar a preencher a primeira linha com o valor 0 ou 4.

![Exemplo](./assets/0004-exemplo.jpg#dark=3)

Porém, se tivessemos a ver a mesma string mas numa [2 way set associative_cache](color:pink),
Porém, se tivéssemos a ver a mesma string mas numa [2 way set associative_cache](color:pink),
só teríamos _miss_ nos primeiros dois acessos, visto que os nossos valores seriam
guardados na primeira e segunda via da primeira linha, e a partir daí conseguiríamos
aceder aos endereços 0 e 4 com sucesso.
Expand All @@ -530,7 +538,7 @@ dar acesso a novos? Em [mapeamento direto](color:purple) não temos escolha, con
[set de associatividade](color:purple) geralmente vemos primeiro se há alguma
[entrada não válida](color:pink), se não escolhemos a entrada que não está a ser usada
há mais tempo (LRU- _least-recently used_), o que é simples para uma via de 2, é gerível
com facilidade para 4, mas mais do que isso é demasiado díficil; nesses casos
com facilidade para 4, mas mais do que isso é demasiado difícil; nesses casos
funciona mais ou menos da mesma forma mas mais [aleatório](color:pink).

:::tip[Exemplos]
Expand Down Expand Up @@ -652,7 +660,7 @@ Existem várias técnicas para otimização de acesso de dados:
Pré-busca, [_prefetching_](color:blue) em inglês, refere-se ao carregamento de um
recurso antes que seja necessário de modo a diminuir o tempo de espera para esse recurso. Assim, um [_software prefetching_](color:pink) não pode ser feito nem
demasiado cedo, visto que os dados podem ser expulsos antes de serem usados, nem
demasiado tarde pois os dados podem não der trazidos a tempo da sua utilizção. Esta
demasiado tarde pois os dados podem não der trazidos a tempo da sua utilização. Esta
técnica é [_greedy_](color:purple). Da mesma forma, o pré-carregamento, ou
[_preloading_](color:blue) em inglês funciona como um pseudo prefetching, usando um
processamento _hit-under-miss_, isto é o acesso antigo é um _miss_ e, por isso, o
Expand Down Expand Up @@ -691,7 +699,7 @@ no esquema abaixo.
Em 1989, McFarling [reduziu _cache misses_ por 75%](color:pink) em caches de mapeamento
direto de 8 kB e blocos de 4 bytes em software. Para tal, foi necessário
[reorganizar os procedimentos em memória](color:purple) para reduzir os
_conflict misses_, assim como fazer um [perfil](color:purple) de modo a analizar os
_conflict misses_, assim como fazer um [perfil](color:purple) de modo a analisar os
conflitos, usando ferramentas que eles desenvolver. Os dados obtidos foram os seguintes:

- [_Merging arrays_](color:yellow): melhoram a localidade espacial através de um único
Expand Down
Loading

0 comments on commit c22958f

Please sign in to comment.