GithubHelp home page GithubHelp logo

kaist-cp / view-hw Goto Github PK

View Code? Open in Web Editor NEW
3.0 3.0 0.0 1.45 MB

Mechanized Proof for Article: "Revamping Hardware Persistency Models: View-Based and Axiomatic Persistency Models for Intel-x86 and Armv8" (PLDI 2021)

Home Page: https://cp.kaist.ac.kr/pmem

License: BSD 2-Clause "Simplified" License

Makefile 0.07% Shell 0.02% Coq 99.89% Dockerfile 0.01%
theorem proof coq-formalization x86 armv8 persistency pldi semantics

view-hw's People

Contributors

jeehoonkang avatar kyeongmincho avatar sunghwanl avatar

Stargazers

 avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

view-hw's Issues

TSO axiom: acyclic po \/ rf

  • W, R는 각각 write, read 라고 하자.
  • x, y, ...는 로케이션이라고 하자.

acyclic po

자명

모든 rfi는 po다

이미 증명되어 있음

po \/ rf = po \/ rfe

po \/ rf
= po \/ rfi \/ rfe (<- rf = rfi \/ rfe)
= po \/ rfe (<- 모든 rfi는 po다)

acyclic po \/ rf

  • po \/ rf = po \/ rfe 이므로 acyclic po \/ rf <-> acyclic po \/ rfe
  • acyclic po 이므로 만약 사이클이 있다면 반드시 rfe가 경로에 있어야 함
  • 그러므로 어떤 사이클 C가 존재한다고 가정하고 C의 시작 부분 경로를 Wx --rfe--> Rx 로 놓자.
  • for all x, y, C는 반드시 Wx --rfe--> Rx; [P]; Wy --rfe--> Ry --po--> Wx 로 이루어져 있어야 한다.
  • 이때, [P] := po | [P]; W; rfe; R; po
  • 주장: Rx; [P]; Wy 에서 [P]tso다. induction [P] !!
    • Rx; po; Wy : dob이므로 tso다.
    • Rx; [Pk]; W; rfe; R; po; Wy
      • W; rfe; Robs
      • R; po; Wydob
      • Rx; [Pk]; W; obs; R; dob; Wy이므로 tso
  • 그러므로 CWx --rfe--> Rx --tso--> Wy --rfe--> Ry --po(dob)--> Wx 이다.
  • 이는 acyclic tso as external 규칙을 위배하므로 이러한 C는 존재하지 않는다.

행동이 나오는지 안 나오는지 실험 (ETRI persistent memory 활용)

  • ETRI에서 persistent memory 머신을 빌릴 수 있음
  • 각 예제를 실제로 구현하여 약 giga번씩 돌려봐서 행동이 나오는지 안 나오는지 확인해보는 작업이 필요. 대략 이 article이 arm/power concurrency에 대해 했던 작업과 비슷한 작업을 한다고 보면 됨
  • priority가 아주 높진 않지만 가능하면 빨리 확인해보도록!
  • 일단 persistent memory가 있다는 가정 하에 benchmark code를 작성해보고 코드가 준비되면 장비를 빌려서 빡세게 실험하고 빠지자!

Px86: update는 바로 영속성을 가질 수 있을까?

둘 중 뭐가 의도인지 인텔 사람에게 물어보기:

  1. nvo에 있어서 update는 fence의 기능만 하고 자기가 쓰는 것을 바로 영속성을 갖게 하진 않는다
  2. 자기가 쓰는 건 바로 영속성을 갖게 한다

2020/05/28 미팅록 (성환님 조인 미팅)

아젠다

  • persistency semantics 개요 및 프로젝트 컨트리뷰션 정리
    • 프로미스 없는 심플한 TSO로 시작하지 않은 이유: AtoP 증명에서 스레드들 간의 인터리빙 처리하기가 힘들기 때문에
    • 빅터 논문 버그 수정에 대한 컨트리뷰션 의의
      • 영속성 오더 자체가 바뀌는 건 아니라서 우리가 쌩뚱맞은 걸 보이는 것은 아니다.
      • 인텔 사람들과 얘기를 해봐야할 것
  • 모델체커
    • 크리스토퍼를 초청해야 할 수도 있다.
    • 영속성 뷰만 보여주는 걸로 한다면 코드 수정이 힘들지 않을 수도 있다.

액션아이템

  • 성환님께 에트리 보고서 드리기
  • POPL 제출 전까지 간간이 성환님에게 테크니컬한 질문하기
  • POPL 제출 끝나고 7월 중순에 다시 한 번 미팅 갖기

Axiom-PARMv8: FO;po;DSB 일 때 persist 안 되는 버그 관련 논의

성환님 질문

Figure 11 (Axiom-PARMv8)의 fl relation 정의에 대한 질문 드립니다.
(dc.cvap가 FO event를 내는 것으로 이해하였는데 혹시 아니라면 알려주시기 바랍니다.)

fl = [W ∩ D]; (ob+ ∩ CL); [FO]; ob+; po; [dsb.sy]
EX: x = 1; dc.cvap; dsb.sy

현재 fl은 위와 같이 정의되어 있는데요, 지금의 정의를 따르면 EX의 dsb.sy가 실행되었다고 해도 x = 1이 persist할 필요가 없는 것으로 보입니다.
pob에 [FO]; po; [dsb.sy]가 추가하고 fl을 아래와 같이 수정해야 하는 것은 아닌지 궁금합니다.
fl = [W ∩ D]; (ob+ ∩ CL); [FO]; ob+; po?; [dsb.sy]

추가로 dsb.sy 외에 FO와 order를 갖는 dsb는 없나요?

교수님 답변

  • 제 생각에 pob는 그대로 놔두고 fl = [W ∩ D]; (ob+ ∩ CL); [FO]; ob*; po?; [dsb.sy]로 바꾸는게 어떨까 합니다. (뒤 ob+ -> ob*).
    아마 증명 어딘가에서 틀렸을텐데 위와 같이 바꾸면 다시 증명도 맞을 것입니다.

  • pob를 그대로 놔두고 싶은 이유는 fence를 ob에서 빼고싶기 때문입니다. Promising-ARM/RISC-V에서처럼... Fence가 오더에 들어가면 더 복잡해지는 것 같아서요.

  • dsb.sy 외에 가령 dsb.stFO와 order를 갖지 않나 추측하긴 합니다만, 명확하진 않습니다.
    Viktor paper에서는 dsb.sy만 다루었고 ("DSB_full" in their paper), ARM reference manual에서도 별다른 논의가 없는데요,
    나중에 ARM 엔지니어에게 물어보는게 좋을 것 같습니다.

custom admit tactic

snu-sf/promising-coq? snu-sf/?? 찾아서 lib/Basics.v 이런데 넣고
admit 모두 "myadmit" ...
Admitted -> Qed

equivalence 증명 방법

일단은 간단히만....

AtoP

모든 A의 행동에 대해 이에 대응하는 어떤 P의 행동이 있다는 것을 증명

  • sim으로 시뮬레이션(같은 행동 존재 찾기)
    • v(eids) > prom view ( v(eids) : eids.map(view_of_eid).fold(U, ㅗ) )
    • vrn, vwo, coh 등에 컨트리뷰트하는 axiomatic 시퀸스를 정의

.
.
.

PtoA

AtoP를 거꾸로?

TSO prom: vro와 vwn은 필요한가?

제안

#29 와 어느정도 연관이 있는 이슈

우선 promising tso에서는,

(R) 모든 readrmw는 바로바로 vrn을 갱신해준다.
(W) 모든 writermw는 무조건 t에다가 쓴다.

한편 기존 promising arm에서는 vrovwo는 barrier를 통해 vrnvwn을 갱신하여 준다.
그러나 promising tso에서는 barrier가 오직 wr일 때에만 유효하다.

때문에 아래의 두 뷰는 이러이러한 이유로 필요하지 않은 것 같다:

  • vro
    • (R) => vrovrn에게 전해줄 게 없다.
    • (W) => vrovwn에게 전해줄 게 없다.
  • vwn
    • (W) => writermw이 딱히 preview를 필요로 하지 않기에 vwn을 사용하지 않는다.

증명

기존 코드(TsoPromising.v)에서 vrovwn을 빼도 증명은 잘 됩니다.

rfi가 TSO에 없는 이유

예시 (store buffering)

T1

x = 1    // (1.1)
r1 = x    // (1.2)
r2 = y    // (1.3)

T2

y = 1    // (2.1)
r3 = y    // (2.2)
r4 = x    // (2.3)

behavior

r2 = r4 = 0

rfi <= tso라면,

  • (1.1) tso (1.2)이고, RR로부터 (1.2) tso (1.3)
  • (2.1) tso (2.2)이고, RR로부터 (2.2) tso (2.3)
  • 그런데 (1.3) -fr-> (2.1), (2.3) -fr-> (1.1) 사이에 tso가 있다. (fr <= obs <= ob= tso)
  • 그러므로 cycle이 생겨 모순.

View-x86 Semantics

local = { cow, view }  // cow = forward bank
cow: loc -> option Time
view: Time

(READ)
(cow1 X).unwrap <= ts
latest X ts view1 mem1
view2 = cow1 X == Some ts ? view1 : view1 U ts
---------------------
{ cow1, view1, mem1 } -(read X ts)-> { cow1, view2, mem1 }

(WRITE)
ts = len mem1
mem2 = mem1 ++ [msg]
---------------------
{ cow1, view1, mem1 } -(write X ts)-> { cow1 U (X->ts), view1, mem2 }

(RMW)
{ cow1, view1, mem1 } -(read X tr)-> { cow2, view2, mem2 }
{ cow2, view2, mem2 } -(write X tw)-> { cow3, view3', mem3 }
latest X tr tw mem2
view3 = view3' U tw
---------------------
{ cow1, view1, mem1 } -(update X tr tw)-> { cow3, view3, mem3 }

(MFENCE)
view2 = view1 U max cow1
---------------------
{ cow1, view1, mem1 } -> { fun _ => None, view2, mem1 }

TODO:

  • rmw에 팬스 같은 거 추가
  • 퍼시스턴스 뷰 어떻게 넣을 것인가
  • px = px-simpl: 뷰의 릴레이션을 주면 된다. v1 ~ v2
    • f(v1) = v2, f = vrn, fwdbank만 남긴 것
    • invariant S가 필요, 예를 들어 S(v1)이라면 "vro <= vrn라는 인배리언트가 있다" 그러므로 vro는 지워도 상관이 없다

Recent changes to ARMv8 persistence (Point of Persistence vs. Point of Deep Persistence)

Latest ARM architecture reference manual: https://developer.arm.com/documentation/ddi0487/fb/ Searching for "persist" leads us to interesting references...

--

78 page says:

ARMv8.2-DCCVADP allows two levels of cache clean to the Point of Persistence by:
• Redefining Point of Persistence, which changes the scope of DC CVAP .
• Defining a Point of Deep Persistence.
• Adding the DC CVADP System instruction.

--

144 page says:

Instructions and data can be held in separate caches or in a unified cache. A cache hierarchy can have one or more
levels of separate instruction and data caches, with one or more unified caches that are located at the levels closest
to the main memory. Memory coherency for cache topologies can be defined using the conceptual points Point of
Unification (PoU), Point of Coherency (PoC), Point of Persistence (PoP), and Point of Deep Persistence (PoDP).

--

2508 page defines PoC, PoU, PoP, PoDP, etc (must-read).

Point of Persistence (PoP)

When ARMv8.2-DCPoP is implemented:
The point in a memory system, if it exists, at or beyond the Point of Coherency, where
a write to memory is maintained when system power is removed, and reliably
recovered when power is restored to the affected locations in memory.

When ARMv8.2-DCPoP and ARMv8.2-DCCVADP are implemented:
The point in a memory system where there is a system guarantee that there is
sufficient energy within the system to ensure that a write to memory will be persistent
if system power is removed.

Point of Deep Persistence (PoDP)

The point in a memory system where any writes that have reached that point are persistent, even
in the event of an instantaneous hardware failure of the power system.

What's the diff? I really cannot understand the diff precisely...

cacheline: 하지 맙시다

  • 경민님, 구두로 논의되었던 안건은 되도록 issue로도 정리해주시길 부탁드려요.
  • PTSO-syn 논문에서 언급되었던 것처럼 우리도 cacheline은 모델링하지 맙시다. 쉽게 지원 가능하다..고 말로 퉁치려 합니다.

action item (2020/1/7)

  • commit, draft PR
  • 마지막 admit 해결, PR merge
  • is_reading, is_writing: 다음 PR, 나랑 다시 만나서...

TSO axiom: 지운 lemma list up

  • internal_rw:
Lemma internal_rw
        p ex
        eid1 eid2
        (PRE: pre_ex p ex)
        (CO2: co2 ex)
        (RF2: rf2 ex)
        (INTERNAL: Execution.internal ex eid1 eid2):
    <<EID1: ex.(Execution.label_is) Label.is_access eid1>> /\
    <<EID2: ex.(Execution.label_is) Label.is_access eid2>>.
  • internal_read_read_po:
Lemma internal_read_read_po
        p ex
        eid1 eid2
        (PRE: pre_ex p ex)
        (CO2: co2 ex)
        (RF2: rf2 ex)
        (INTERNAL: Execution.internal ex eid1 eid2)
        (EID1: ex.(Execution.label_is) Label.is_read eid1)
        (EID2: ex.(Execution.label_is) Label.is_read eid2):
    Execution.po eid1 eid2.
  • ob_read_read_po:
Lemma ob_read_read_po
        p ex
        eid1 eid2
        (PRE: pre_ex p ex)
        (CO1: co1 ex)
        (CO2: co2 ex)
        (RF1: rf1 ex)
        (RF2: rf2 ex)
        (RF_WF: rf_wf ex)
        (INTERNAL: acyclic (Execution.internal ex))
        (OB: Execution.ob ex eid1 eid2)
        (EID1: ex.(Execution.label_is) Label.is_read eid1)
        (EID2: ex.(Execution.label_is) Label.is_read eid2):
    Execution.po eid1 eid2.
  • po_loc_write_is_co:
Lemma po_loc_write_is_co
        ex eid1 eid2 loc
        (CO1: Valid.co1 ex)
        (INTERNAL: acyclic (Execution.internal ex))
        (PO: Execution.po eid1 eid2)
        (LABEL1: ex.(Execution.label_is) (Label.is_writing loc) eid1)
        (LABEL2: ex.(Execution.label_is) (Label.is_writing loc) eid2):
    ex.(Execution.co) eid1 eid2.

TSO: dmb 처리

axiomatic

bob를 정의할 때 다음과 같은 방식으로 사용되고 있음 (is_dmb_wr을 그대로 가져다 씀):

Definition bob (ex:t): relation eidT :=
    ⦗ex.(label_is) Label.is_write⦘ ⨾
     po ⨾
     ⦗ex.(label_is) (Label.is_barrier_c Barrier.is_dmb_wr)⦘ ⨾
     po ⨾
     ⦗ex.(label_is) Label.is_read⦘.

promising

기존에 아래와 같이 정의된 dmb를 tso에 맞게 재정의하는 게 숙제임:

Inductive dmb (rr rw wr ww:bool) (lc1 lc2:t): Prop :=
  | dmb_intro
      (LC2: lc2 =
            mk
              lc1.(coh)
              (joins [lc1.(vrn); ifc rr lc1.(vro); ifc wr lc1.(vwo)])
              (joins [lc1.(vwn); ifc rw lc1.(vro); ifc ww lc1.(vwo)])
              lc1.(vro)
              lc1.(vwo))
  .

이전에 언급된 바 (#4) 는 아래와 같음:

match (rr, rw, wr, ww) {
    (_, _, true, true) => mfence,
    (_, _, false, true) => sfence,
    _ => nop
}

질문

  • axiomatic과 promising에서 dmb 이름을 그대로 고수하는 게 맞을까요?
  • sfence는 추후에 persisence(wb, fl, fo)가 적용될 때에만 의미를 가지고 지금 단계에서는 nop과 다를 바가 없는데 고려할 필요가 있을까요?
    • 다시 말해, persistence는 Promising TSO를 완전히 끝내고 나서 고려하는 게 더 편하지 않을까요?
    • 고려하지 않는다면 dmb에서 의미있는 파라미터는 wr 밖에 남지 않으므로 정의는 아래와 같이 단순화할 수 있을 것 같습니다:
Inductive dmb (lc1 lc2:t): Prop :=
  | dmb_intro
      (LC2: lc2 =
            mk
              lc1.(coh)
              (joins [lc1.(vrn); lc1.(vwo)])
              lc1.(vwn)
              lc1.(vro)
              lc1.(vwo))
  .

TSO: rmw_failure의 pre-view/post-view

pre-view

ts1

x = 1
mfence
r1 = y	// 0

ts2

y = 1
r2 = CAS(x, 666, 42)		// fail returning 0?
  • 허용되지 않는다. "fail returning 1"이어야 한다.
  • rmw_failure의 pre-view는 vrn이(like read step) 아닌, join(vrn, vwo)이어야할 것 같다

post-view

ts1

z = 1
mfence
r1 = y	// 0

ts2

y = 1
r2 = CAS(x, 666, 667)	// fail returning 0
r3 = z	// 0?
  • 허용되지 않는다. r31이어야 한다.
  • rmw_failure은 vrn을 join(vrn, vwo)으로 갱신시커야할 것 같다(마치 barrier처럼)

ARM axiom: internal acyclic -> irreflexive 도입 가능?

ARM에선 다음 relation이 acyclic임을 요구:
Definition internal (ex:t): relation eidT := (po_loc ex) ∪ (fr ex) ∪ ex.(co) ∪ ex.(rf).

  • irrefl po; fr, irrefl po; co, irrefl po; rf셋이 irreflexive임을 요구만해도 충분할 것 같고
  • 그게 더 theory가 간단해지지 않나

persistency equivalence proof

pmem에 남는 메모리의 상태를 나타내는 smem(: Loc->Val)을 두자.

Axiomatic.persisted

Axiomatic.persisted p ex smem

  • p가 실행되다가 ex까지 실행되고 crash가 났을 때 smem이 pmem에 남을 것이라는 의미이다.
  • smem에 있는 write에 co* 가 있는 write들은 모두 dom(fl)에 있다
  • uninit도 고려해야 함

Promising.persisted

Promising.persisted p m smem

  • p가 실행되다가 m까지 도달하고 crash가 났을 때 smem이 pmem에 남을 것이라는 의미이다.
  • 로케이션마다 per 뷰를 기반으로 최신(latest)보다 큰 메시지들 중 아무거나 저장된다.

per

Supporting TSO

Difficulties

language

  • missing rmw
  • awkward encoding of barriers (sfence = dmb ww, mfence = dmb full)

promising

  • message, memory는 ARM/Intel 공통. 끄집어내기?
  • 다른 것들은 아키텍쳐별로 따로

TODO

Axiomatic TSO === Promising TSO ?

Causality test case 1

# Initially, x = y = 0

# Thread 1
1: r1 = x
2: if r1 >= 0
3:   y = 1

# Thread 2
4: r2 = y
5: x = r2

# Behavior in question:
r1 == r2 == 1
  • Axiomatic
    • DISALLOWED
    • if 1 --dob--> 3 --rfe--> 4, 4--dob--> 5 --rfe--> 1
  • Promising
    • DISALLOWED
    • 1이 먼저 실행되면 r10
    • 4가 먼저 실행되면 r20

Causality test case 2

# Initially, x = y = 0

# Thread 1:
1: r1 = x
2: r2 = x
3: if r1 == r2
4:   y = 1

# Thread 2:
5: r3 = y
6: x = r3

# Behavior in question:
r1 == r2 == r3 == 1
  • Axiomatic
    • DISALLOWED
    • if 1 --dob--> 2 --dob--> 4 --rfe--> 5, 5--dob--> 6 --rfe--> 1
  • Promising
    • DISALLOWED
    • 1이 먼저 실행되면 r10
    • 5가 먼저 실행되면 r30

Causality test case 3

# Initially, x = y = 0

# Thread 1:
1: r1 = x
2: r2 = x
3: if r1 == r2
4:   y = 1

# Thread 2:
5: r3 = y
6: x = r3

# Thread 3:
7: x = 2

# Behavior in question:
r1 == r2 == r3 == 1
  • Axiomatic
    • DISALLOWED
    • if 1 --dob--> 2 --dob--> 4 --rfe--> 5, 5--dob--> 6 --rfe--> 1
  • Promising
    • DISALLOWED
    • 1이 먼저 실행되면 r10
    • 5가 먼저 실행되면 r30

Causality test case 4

# Initially, x = y = 0

# Thread 1:
1: r1 = x
2: y = r1

# Thread 2:
3: r2 = y
4: x = r2

# Behavior in question:
r1 == r2 == 1
  • Axiomatic
    • DISALLOWED
    • if 1 --dob--> 2 --rfe--> 3, 3--dob--> 4 --rfe--> 1
  • Promising
    • DISALLOWED
    • 1이 먼저 실행되면 r10
    • 3이 먼저 실행되면 r20

Causality test case 5

# Initially, x = y = z = 0

# Thread 1:
1: r1 = x
2: y = r1

# Thread 2
3: r2 = y
4: x = r2

# Thread 3
5: z = 1

# Thread 4
6: r3 = z
7: x = r3

# Behavior in question:
r1 == r2 == 1, r3 == 0.
  • Axiomatic
    • DISALLOWED
    • if 5 --rfe--> 6, r3 == 0
    • else if 1 --dob--> 2 --rfe--> 3, 3--dob--> 4 --rfe--> 1
  • Promising
    • DISALLOWED
    • 1이 먼저 실행되면 r10
    • 3이 먼저 실행되면 r20
    • 5가 먼저 실행되면 r31
    • 6이 먼저 실행되면 7 실행 여부와 관계 없이 1에서 r10

Causality test case 6

# Initially A = B = 0

# Thread 1
1: r1 = A
2: if (r1 == 1)
3:   B = 1

# Thread 2
4: r2 = B
5: if (r2 == 1)
6:   A = 1
7: if (r2 == 0)
8:   A = 1

# Behavior in question:
r1 == r2 == 1
  • Axiomatic
    • DISALLOWED
    • if 1 --dob--> 3 --rfe--> 4, 4--dob--> 6 --rfe--> 1
    • if 4 --dob--> 8 --rfe--> 1, 1--dob--> 3 --rfe--> 4
  • Promising
    • DISALLOWED
    • 1이 먼저 실행되면 r10
    • 4가 먼저 실행되면 r20

Causality test case 7

# Initially, x = y = z = 0

# Thread 1:
1: r1 = z
2: r2 = x
3: y = r2

# Thread 2:
4: r3 = y
5: z = r3
6: x = 1

# Behavior in question:
r1 == r2 == r3 == 1.
  • Axiomatic
    • DISALLOWED
    • if 4 --dob--> 5 --dob--> 6--rfe--> 2, 2 --dob--> 3 --rfe--> 4
  • Promising
    • DISALLOWED
    • 1이 먼저 실행되면 r10
    • 4가 먼저 실행되면 r30

Causality test case 8

# Initially, x = y = 0

# Thread 1:
1: r1 = x
2: r2 = 1 + r1*r1 - r1
3: y = r2

# Thread 2:
4: r3 = y
5: x = r3

# Behavior in question:
r1 == r2 == 1
  • Axiomatic
    • DISALLOWED
    • if 1 --dob--> 2 --dob--> 3 --rfe--> 4, 4 --dob--> 5 --rfe--> 1
  • Promising
    • DISALLOWED
    • 1이 먼저 실행되면 r10
    • 4가 먼저 실행되면 r30 => r10

Causality test case 9

# Initially, x = y = 0

# Thread 1:
1: r1 = x
2: r2 = 1 + r1*r1 - r1
3: y = r2

# Thread 2:
4: r3 = y
5: x = r3

# Thread 3:
6: x = 2

# Behavior in question:
r1 == r2 == 1
  • Axiomatic
    • DISALLOWED
    • if 1 --dob--> 2 --dob--> 3 --rfe--> 4, 4 --dob--> 5 --rfe--> 1
  • Promising
    • DISALLOWED
    • 1이 먼저 실행되면 r10
    • 4가 먼저 실행되면 r30
      • 그 뒤 1이면 r10
      • 그 뒤 6 뒤에 1이면 r12

Causality test case 10

# Initially, x = y = z = 0

# Thread 1:
1: r1 = x
2: if (r1 == 1)
3:   y = 1

# Thread 2
4: r2 = y
5: if (r2 == 1)
6:   x = 1

# Thread 3
7: z = 1

# Thread 4
8: r3 = z
9: if (r3 == 1)
10:   x = 1

# Behavior in question:
r1 == r2 == 1, r3 == 0.
  • Axiomatic
    • DISALLOWED
    • impossible
  • Promising
    • DISALLOWED
    • 1이 먼저 실행되면 r10
    • 4가 먼저 실행되면 r20
    • 7이 먼저 실행되면 8에서 r31
    • 8이 먼저 실행되면,
      • 1이 먼저 실행되면 r10
      • 4가 먼저 실행되면 r20

Causality test case 11

# Initially, x = y = z = 0

# Thread 1:
1: r1 = z
2: w = r1
3: r2 = x
4: y = r2

# Thread 2:
5: r4 = w
6: r3 = y
7: z = r3
8: x = 1

# Behavior in question:
r1 == r2 == r3 == r4 == 1
  • Axiomatic
    • DISALLOWED
    • if 8 --rfe-->3, 3 --dob--> 4 --rfe--> 6 --dob-->8
  • Promising
    • DISALLOWED
    • 1이 먼저 실행되면 r10
    • 비록 w가 initially 1일지라도 5가 먼저 실행되면,
      • 1이 먼저 실행되면 r10
      • 6이 먼저 실행되면 r30

Causality test case 12

# Initially, x = y = 0; a[0] = 1, a[1] = 2

# Thread 1
1: r1 = x
2: a[r1] = 0
3: r2 = a[0]
4: y = r2

# Thread 2
5: r3 = y
6: x = r3

# Behavior in question:
r1 == r2 == r3 == 1
  • Axiomatic
    • DISALLOWED
    • if 3 --dob--> 4 --rfe--> 5, 5 --dob--> 6 --rfe--> 1 --dob--> 3
  • Promising
    • DISALLOWED
    • 1이 먼저 실행되면 r10
    • 5가 먼저 실행되면 r30

Causality test case 13

# Initially, x = y = 0

# Thread 1:
1: r1 = x
2: if (r1 == 1)
3:   y = 1

# Thread 2:
4: r2 = y
5: if (r2 == 1)
6:   x = 1

# Behavior in question:
r1 == r2 == 1
  • Axiomatic
    • DISALLOWED
    • if 3 --rfe--> 4, 4 --dob--> 6 --rfe--> 1 --dob--> 3
  • Promising
    • DISALLOWED
    • 1이 먼저 실행되면 r10
    • 4가 먼저 실행되면 r20

Causality test case 14

# Initially, a = b = y = 0, y is volatile

# Thread 1:
1: r1 = a
2: if (r1 == 0)
3:   y = 1
4: else
5:   b = 1

# Thread 2:
6: do {
7:   r2 = y
8:   r3 = b
9:   } while (r2 + r3 == 0);
10: a = 1;

# Behavior in question:
r1 == r3 == 1; r2 == 0
  • Axiomatic
    • DISALLOWED
    • if 10 --rfe--> 1, 1 --dob--> 5 --rfe--> 8 --dob--> 10
  • Promising
    • DISALLOWED
    • 1이 먼저 실행되면 r10
    • 1이 실행되기 전에 7, 8은 무한 루프

Causality test case 15

# Initially, a = b = x = y = 0, x and y are volatile

# Thread 1:
1: r0 = x
2: if (r0 == 1)
3:   r1 = a
4: else 
5:   r1 = 0
6: if (r1 == 0)
7:   y = 1
8: else
9:   b = 1

# Thread 2:
10: do {
11:   r2 = y
12:   r3 = b
13:   } while (r2 + r3 == 0);
14: a = 1;

# Thread 3:
15: x = 1

# Behavior in question:
r0 == r1 == r3 = 1; r2 == 0
  • Axiomatic
    • DISALLOWED
    • if 15 --rfe--> 1 --dob--> 3 --dob--> 9 --rfe--> 12, 12 --dob--> 14 --rfe--> 3
  • Promising
    • DISALLOWED
    • 1이 먼저 실행되면 r00
    • 15이 먼저 실행되면
      • 1이 먼저 실행되면 3에서 r10
      • 11, 12는 7, 9가 실행되기 전까지 무한 루프

Causality test case 16

# Initially, x = 0

# Thread 1:
1: r1 = x
2: x = 1

# Thread 2:
3: r2 = x 
4: x = 2

# Behavior in question:
r1 == 2; r2 == 1
  • Axiomatic
    • DISALLOWED
    • if 2 --rfe--> 3 , 3 --dob--> 4 --rfe--> 1 --dob--> 2
  • Promising
    • DISALLOWED
    • 1이 먼저 실행되면 r10
    • 3이 먼저 실행되면 r20

Causality test case 17

# Initially, x = y = 0

# Thread 1:
1: r3 = x
2: if (r3 != 42)
3:   x = 42
4: r1 = x
5: y = r1

# Thread 2:
6: r2 = y
7: x = r2

# Behavior in question:
r1 == r2 == r3 == 42
  • Axiomatic
    • DISALLOWED???
    • if 1 --dob--> 3, 1 --dob--> 4 --fr--> 7 --rfe--> 1
  • Promising
    • DISALLOWED
    • 1이 먼저 실행되면 r30
    • 6이 먼저 실행되면 r20

Causality test case 18

# Initially,  x = y = 0

# Thread 1:
1: r3 = x
2: if (r3 == 0)
3:   x = 42
4: r1 = x
5: y = r1

# Thread 2:
6: r2 = y
7: x = r2

# Behavior in question:
r1 == r2 == r3 == 42
  • Axiomatic
    • DISALLOWED???
    • if 1 --dob--> 3, 1 --dob--> 4 --fr--> 7 --rfe--> 1
  • Promising
    • DISALLOWED
    • 1이 먼저 실행되면 r30
    • 6이 먼저 실행되면 r20

Causality test case 19

# Initially,  x = y = 0

# Thread 1:
1: join thread 3
2: r1 = x
3: y = r1

# Thread 2:
4: r2 = y
5: x = r2

# Thread 3:
6: r3 = x
7: if (r3 != 42)
8:   x = 42

# Behavior in question:
r1 == r2 == r3 == 42
  • Axiomatic
    • DISALLOWED
    • if 6 --dob--> 8, 8 --rfe--> 2 --dob--> 3 --rfe--> 4 --dob--> 5 --rfe--> 6
  • Promising
    • DISALLOWED
    • 4가 먼저 실행되면 r20
    • 6이 먼저 실행되면 r30

Causality test case 20

# Initially,  x = y = 0

# Thread 1:
1: join thread 3
2: r1 = x
3: y = r1

# Thread 2:
4: r2 = y
5: x = r2

# Thread 3:
6: r3 = x
7: if (r3 == 0)
8:   x = 42

# Behavior in question:
r1 == r2 == r3 == 42
  • Axiomatic
    • DISALLOWED
    • if 6 --dob--> 8, 8 --rfe--> 2 --dob--> 3 --rfe--> 4 --dob--> 5 --rfe--> 6
  • Promising
    • DISALLOWED
    • 4가 먼저 실행되면 r20
    • 6이 먼저 실행되면 r30

TSO prom: write, rmw 스탭에 ts 조건 추가

@jeehoonkang
write_incrrmw_incr를 증명하던 중 ts에 대한 조건이 추가되어야 할 것 같아서 아래의 CHECK대로 바꿔보았는데, 이 제안이 맞는지 여쭙습니다.

write

Inductive write (vloc vval res:ValA.t (A:=unit)) (ts:Time.t) (tid:Id.t) (lc1:t) (mem1: Memory.t) (lc2:t) (mem2: Memory.t): Prop :=
  | write_intro
      loc val
      view_loc view_val
      view_post
      (LOC: loc = vloc.(ValA.val))
      (VIEW_LOC: view_loc = vloc.(ValA.annot))
      (COH: lt (lc1.(coh) loc).(View.ts) ts) (* CHECK: added due to write_incr *)
      (VAL: val = vval.(ValA.val))
      (VIEW_VAL: view_val = vval.(ValA.annot))
      (VIEW_POST: view_post = View.mk ts bot)
      (MEM: Memory.append (Msg.mk loc val tid) mem1 = (ts, mem2))
      (RES: res = ValA.mk _ 0 bot)
      (LC2: lc2 =
            mk
              (fun_add loc view_post lc1.(coh))
              lc1.(vrn)
              (join lc1.(vwn) view_post)
              lc1.(vro)
              (join lc1.(vwo) view_post))
  .

rmw

Inductive rmw (vloc vold vnew:ValA.t (A:=unit)) (ts:Time.t) (tid:Id.t) (lc1:t) (mem1:Memory.t) (lc2:t) (mem2:Memory.t): Prop :=
  | rmw_intro
      loc old new old_ts
      view_post
      (LOC: loc = vloc.(ValA.val))
      (LATEST: Memory.latest loc old_ts (lc1.(coh) loc).(View.ts) mem1)  (* CHECK: added due to rmw_incr *)
      (COH: lt (lc1.(coh) loc).(View.ts) ts) (* CHECK: added due to rmw_incr *)
      (* (LATEST: Memory.latest loc old_ts ts mem1)  (* CHECK: removed 'cause it's too strong *) *)
      (MSG: Memory.read loc old_ts mem1 = Some old)
      (OLD: vold.(ValA.val) = old)
      (NEW: new = vnew.(ValA.val))
      (VIEW_POST: view_post = View.mk ts bot)
      (MEM: Memory.append (Msg.mk loc new tid) mem1 = (ts, mem2))
      (LC: lc2 =
            mk
              (fun_add loc view_post lc1.(coh))
              (join lc1.(vrn) view_post)
              (join lc1.(vwn) view_post)
              (join lc1.(vro) view_post)
              (join lc1.(vwo) view_post))
  .

TSO: rmw old_ts 재변경

문제

이전에 rmw step의 old_ts에 대한 조건으로 exclusive를 사용하기로 한 적이 있음:
"old_ts부터 ts까지 tid가 아닌 곳에서 쓴 메시지는 없다"

  • 그런데 같은 스레드에서 rmw 이전에 메시지를 썼다면, 그 이전 메시지를 old_ts로 잡는 게 가능하다
  • 또한 TsoPFtoA1 에서 RPROP1 증명이 안 된다(혹은 복잡해진다)

예시

X = 666
r1 = CAS(X, 0, 42) # success

성공시켜주면 안 된다..

경과

  • 이전 제안대로 "old_ts부터 ts-1 까지 메시지가 없다" 로 조건을 바꿈
  • 증명은 잘 됨

질문

  • ARM 에서는 ex read와 ex write 사이에 또 다른 write이 들어가도 허용되는 것 같은데 원래 그런 건가요?

#45 merge 전 체크사항

  • coq 8.11 디펜던시
    • Makefile 도 수정 필요 (quick is now deprecated)
  • 파일 정리
    • ARM/TSO 공통 렘마 한 곳에 묶고
    • tsopromising.v 날리기
  • 지저분한 destruct (equiv_dec...) -> eqvtac

ETRI 발표자료 송부

  • 부가 설명을 위한 annotation을 추가해서 송부
  • 급한 건 아니니 준비 되는 대로 송부

HintDB

@jeehoonkang

  • deprecated라는 건 Hint Resolve foo와 같이 힌트를 core에 implicitly 등록하는 것만을 의미하는 것이었습니다. Hint Resolve foo: core 같은 식으로 explicitly 등록하는 것 자체는 상관이 없긴 합니다.
  • 기존에 레포 안에 있는 모든 힌트(hahn 제외)들이 core에 등록된 것 같은데 이들을 전부 hint db를 따로 파서 바꿔주어야 할까요?
  • 일단 hint db 만들고 힌트들 등록한 뒤에 eauto 가 제대로 안 먹어서 애를 먹는 상태입니다. (core에 등록시 잘 됩니다)

TSO: Store buffering 예제 불일치 문제

예시 (store buffering)

T1

x = 1
r1 = x
r2 = y

T2

y = 1
r3 = y
r4 = x

behavior

r2 = r4 = 0
  • Axiomatic TSO에서는 허용된다
  • 현재의 Promising TSO에서는 허용되지 않는다
  • AtoP 증명에서 rfi와 관련된 admit도 이와 관련되었을 것으로 사료됨 (TODO)

제안

  • Promising에 Fwdbank를 추가

PLDI 2021 할일 (deadline: 2020년 11월 중순)

Promising TSO

  • Axiomatic 정의
  • Promising 정의
  • AtoP
  • PtoPF
  • PFtoA
    • rmw 관련한 sim_th PROP들 수정
    • external, corw, cowr
  • PFtoV(#46)
  • VtoP

Promising ARM for Persistency

  • Axiomatic 정의
  • Promising 정의
  • AtoP
  • PtoPF
  • PFtoA

Promising TSO for Persistency

  • [W];po;[FO];po;[SF] 같은 식으로 실행했을 때 persist가 되지 않는 행동이 일어나는지 실험방법 강구 및 실험 (#34)
  • Axiomatic 정의 (pob)
  • Promising 정의 (persistency view)
  • AtoP (pob)
  • PtoPF (pob)
  • PFtoA (pob)
  • PFtoV (pob)
  • VtoP (pob)
  • Axiomatic dom 정의
  • AtoP (dom ~ global per view)
  • PtoPF (global per view)
  • PFtoA (dom ~ global per view)
  • PFtoV (global per view)
  • VtoP (global per view)

증명 끝났는데 시간이 남는다면

  • 캐시라인 추가(#63)
  • ARM internal 단순화 (#23)
  • ARM/TSO 코드 통합 리팩토링

persistent library?

  • (빅터논문에서는) MSQ?

Model Checker

  • 구현
  • 벤치마크

논문 작성

  • Coq과의 불일치 고치기
  • README 정리

Axiom-PARMv8

잠정적으로 아래 모델을 Axiom-PARMv8 모델로 사용하려고 합니다.

pob = [W U R]; po; [dmb.sy U dsb.sy]; po; [FO] U
      [W U R]; (po ∩ CL); [FO] U
      [FO]; (po ∩ CL); [FO]    // can be removed
fl = [W ∩ D]; (ob+ ∩ CL); [FO]; po; [dsb.sy]

Formalization에서 [dm(s)b.sy] = [dm(s)b.rr ∩ rw ∩ wr ∩ ww]으로 정의됩니다.

추가로 x86 또한 아래와 같이 simplify 가능할 것으로 보입니다.

pob = [W ∪ U]; po; [FL]
   ∪ ([U]; po; [FO])
   ∪ [W]; (po ∩ CL); [FO]
   ∪ [R]; po; [FL ∪ FO]
fl = [W ∩ D]; (ob+ ∩ CL); [FL]
  ∪ [W ∩ D]; (ob+ ∩ CL); [FO]; po; [MF ∪ SF ∪ U ]

Tso AtoP: 증명

진행중

invariant

  • coh(l) <= U e(l)'s w timestamp
  • vro <= U e's w timestamp
  • vro <= U e's r timestamp
  • vwo <= U e's w timestamp
  • vrn <= U e's w timestamp
  • vrn <= U e's r timestamp

Read

  • forall t where tr < t <= vrn U coh(e's r loc), e(t)'s r loc =/= l

Write

  • vwn <= tw

Extending co in Px86

@jeehoonkang @Sung-HwanLee

co 확장에 관하여 몇 가지 의구심이 드는 부분이 있습니다
(가정: alternative Figure 10에서 fl의 ob+_sclco로 대체한다면)

P <= W_D

  • co확장으로 인해 [FL]dom(co?;[P])이 더 이상 서로소가 아니게 됩니다.
  • 그런데 dom(co?;[P]) <= P <= W_D (Figure 10) 이므로 어떤 e(in [FL]) in W_D 가 될 수 있습니다.
  • 예시: flush x; x=1; flush x

coi -> po

"coi -> po"가 더 이상 참이 아닌데 이는 조금 이상합니다.
예시: flush x; x=1 에서 x=1 -co-> flush x 가 가능하고 x=1 in dom(fl) 이 되어버립니다.

  • 방법1: irrefl (co; po) 추가
  • 방법2: alternative에서 제거했던 pob 내용들을 다시 살림
    • FL; po; W
    • FO; po_cl; W (이건 Px86에는 없는 규칙입니다)

짧은 생각으로는 방법1이 더 심플한 것 같긴 한데 무엇이 맞는진 잘 모르겠습니다.

[FLO]; scl; [FLO] <= co

  • co 확장에 FLO끼리의 오더도 들어갈 필요가 있는지 의문입니다. 반례가 잘 생각이 안 나서...
  • 들어가게 된다면 기존 PtoA 증명이 좀 깨지게 됩니다.
    • "a -ob-> FL -ob-> b 이면 a -ob-> b 이다." 라는 렘마가 있었는데 이는 더 이상 참이 아니게 되기 때문입니다.
    • 예시: x=1; flush y; flushopt y

TSO: PF <= PX 증명 전략

  • PF의 실행이 있을 때,
    • 메모리 리스트가 있고
    • 각 스레드별로 이벤트들이 순서대로 있다.
  • 같은 결과를 내는 PX의 실행이 있고 /\ 그 실행은 PF의 이벤트들을 다음과 같이 정렬하면 된다:
    1. 해당 step 후 vwn의 상태에 따라 내림차순
    2. (vwn이 같다면) w/u가 r 보다 먼저
    3. (r-r 순서라면) 같은 스레드 내에선 앞에 r이 먼저

Axiom-PARMv8: [R]; po; dmb.sy; po; [FO] ob 추가 관련 논의

질문

안녕하세요, 코드에 대해 코멘트 드릴 부분은 없고 질문이 몇 가지 있습니다.

  • 이 질문은 논문의 Figure 11/12에 관한 내용입니다.
X = 1
Y = 1 [rel]
||
a = Y  // 1
dmb.sy
flush X
dsb.sy

Figure 12에 따르면 [X = 1] -ob-> [flush X] 가 존재합니다.
즉, dsb.sy 실행 후 X = 1이 persist해야 하는 것으로 보입니다.
Figure 11의 경우 [a = Y] -ob-> [flush X]가 없어 dsb.sy 실행 이후에도 X = 1이 persist할 필요가 없는 것으로 보이는데, 맞나요?

여기까지 맞다면 아래와 같은 변형에 대해서도 궁금합니다.

X = 1
Y = 1 [rel]
||
a = Y  // 1
dmb.ld (= dmb r, rw)
flush X
dsb.sy
X = 1
Y = 1 [rel]
||
a = Y  [acq] // 1
flush X
dsb.sy

만약 첫번째 프로그램에서 X = 1이 persist하다면 위 두 프로그램에서 X = 1이 persist하지 않다는 것이 굉장이 의아합니다.
또한 만약 이것이 참인 경우 현재 promising-ARM에서 구현하기 위해서는 다른 view component를 추가해야할 것으로 보입니다.

  • Promising-ARM에서 persistency를 global persistent view 이후의 메시지들이 persist 하다고 정의할 예정인가요?

  • Figure 11 및 12에서 ARM-WB-WB는 없어도 equivalent한 것이 아닌지 궁금합니다.


개인적으로 지금 ARM spec (Figure 12)가 다소 작위적이지 않나 생각합니다.
dmb.ld; flush 또는 flush; dmb.st의 order가 보존되지 않을 이유가 없는데 아마 기존 연구에서 충분한 이해가 이루어지지 않은 것 같습니다.
(dmb.st의 경우 ARM spec에 따르면 전후 write 사이에만 order를 부여하므로 아닐 수도 있습니다.
C11의 release fence는 dmb.sy로 컴파일 됩니다.)
acquire read나 release write의 경우도 마찬가지라고 봅니다.
이 부분에 대해서 ARM 개발자들과도 조금 더 논의해서 보완하면 어떨까 합니다.
다만 우리 구현에서는 barrier가 rr/rw/wr/ww로 나뉘어 있는데, 이 경우 flush를 write로 볼지 read로 볼지 애매한 부분이 생기긴 합니다.

설 연휴 할 일

  • 머지 (#27)
  • 예제 정리 체계적으로
    • 예제 리스트업
    • 두 시맨틱스에 대해서 허용이 되는 건지 안 되는 건지 (데피니션을 중심으로)
    • 예스 or no or 모르겠다
  • proof
    • 먼저: 했던 얘기를 문서로...
    • AtoP.v -> TsoAtoP.v

TSO: rmw의 vro

문제

PFtoA4SL에서의 증명은

  • 어떤 뷰에 영향을 미치는 label이 갖게 될 post-view가
  • 실제 그 뷰보다
  • 언제나 작거나 같다는 것

을 보이는 것 같습니다.

예를 들어 vro라면,

  • 영향을 미치는 건 (R \/ U); po 가 되고
  • U일 경우 갖게 되는 post-view는 U가 vnew를 쓴 시간, 즉 ts가 됩니다.
  • 그러므로 ts <= vro를 증명해야 합니다.

그런데 예전에 lc2.vro = join(lc1.vro, old_ts) 로 놓기로 얘기가 되었습니다.
다시 말해 ts <= old_ts를 증명해야 되는데 이는 말이 안 되므로 rmw스탭에서의 vro를 바꿔야할 것 같습니다.

제안

rmw의 가까운 친척인 read를 보면 vro를 메시지의 뷰로 조인하는 것이 아닌 post-view로 조인합니다.
vro를 "어디 있는 메시지까지 읽었냐" 보다는 "읽으면서 어디까지 보게 되었냐" 라고 해석한다면,
rmw의 vro도 역시 post-view, 즉 ts로 주어야 할 것 같습니다

Promising TSO에 fwd가 없어야하는 이유

예제

t1

(a) X := 1;
(b) r0 := Y; // 1 from (f)
(c) r1 := X // 2 from (e)

t2

(d) r0 = X; // 1 from (a)
(e) X = 2;
(f) Y = 1

(a) -> (d) -> (e) -> (f) -> (b) -> (c) 순으로 실행될 때,
(c)는 2를 읽어야 한다.

TSO: read step의 post view

상황

  • ARM에서 read 스탭의 post-view는 res.annot에 담아두고 있어서 post-view를 참조할 때 res.annot을 보면 됨
  • 그러나 TSO에서는
    • annot을 사용하지 않음 (전부 bot 처리)
    • write이나 rmw같은 경우 lc2.coh(x) = post-view 라는 사실을 이용하여 lc2.coh(x)를 참조하면 되지만
    • read는 lc2.coh(x) = join(lc1.coh(x), post-view) 이므로 lc2.coh(x)가 직접적으로 post-view를 나타내지 않음

타파

  • TSO read에서 lc2.coh(x) = join(lc1.coh(x), post-view) 라는 것은 ARM에 있던 걸 그대로 가져와서 생기는 문제라고 봄
  • TSO에서는 rr 간에 오더가 있으므로 사실 lc2.coh(x) = post-view로 두어도 무방할 것처럼 보임
  • 다시 말해 언제나 lc1.coh(x) <= post-view

예시

initially, X[0] = X[1] = 0

t1

X[0] = 1

t2

a = X[0]   // 1
b = X[a]   // 0
c = X[1]   // 0
  • ARM이라면,
    • b에서 coh(X[1])은 0 -> 1로 바뀐다. (레지스터뷰에 의해)
    • c에서 post-view(=0)가 coh(X[1])(=1) 보다 작아지는 상황이 발생한다.
    • 그러므로 read할 때 임의의 주소 l에 대하여 lc2.coh(l)는 join(lc1.coh(l), post-view)가 되는 게 맞다
  • 그러나 TSO에서는,
    • b에서 coh(X[1])은 0 -> 1로 바뀐다. (vrn에 의해)
    • c에서 post-view(=1)는 coh(X[1])(=1) 과 같다.
    • 아마도 read에서 coh가 post-view 보다 큰 경우는 없는 것으로 보인다.

문제

다음 중 하나를 선택:
1. read 역시 write나 rmw처럼 lc2.coh(x) = post-view 로 수정. 이 경우 read 스탭후 어떠한 뷰도 작아지지는 않는다는 read_incr lemma를 증명해야 함
2. TsoPFtoA4SL 증명 중에 coh가 post-view보다 커지는 일은 없다는 것을 증명
3. read에서 post-view를 찾는 다른 방법을 강구

사실상 1과 2는 같은 증명을 해야하며 어디서 증명하느냐의 차이

7/20 미팅 내용

매뉴얼로 더 알긴 힘든 것 같음

교수님 생각:

  • 아마도 우리가 이해한 게 맞는 것 같음
  • 마이크로아키텍처: dsb가 남의 데이터 캐시를 기다리진 않을 것 같음
  • 프로미싱 시맨틱스: 글로벌 퍼시스턴시 뷰에 메시지는 좀 이상함

그럼 이제 어떡할지,

  • 교수님이 빅터그룹에 연락 진행
  • 동시에 증명도 진행합시다

FO; po; FO 지우냐
-> 될 것 같은데, 나중에 핸드프루프를 해본다

케임브리지 dc 오퍼레이션 논문

  • 여기에 따르면 퍼메시지 퍼시스턴시뷰는 필요없을 것 같음

vnew -> vrn 코멘트

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.