ollama psを使うと、現在メモリにロードされているモデルを確認することが出来る。
NAME ID SIZE PROCESSOR UNTIL llama3.1:latest 91ab477bec9d 6.7 GB 100% GPU 4 minutes from now
ollama psの動作をトレース
ollama psは以下のメソッドにより実行される。
psCmd := &cobra.Command{ Use: "ps", Short: "List running models", PreRunE: checkServerHeartbeat, RunE: ListRunningHandler, }
ollama runと同様に、checkServerHeartbeatでサーバーが起動されているかを確認し、ListRunningHandlerにおいてサーバーにロードされるモデルの情報を取得、表示する。
ListRunningHandlerは50行ほどのメソッドなので、ここに貼り付けてみます。
func ListRunningHandler(cmd *cobra.Command, args []string) error { client, err := api.ClientFromEnvironment() if err != nil { return err } models, err := client.ListRunning(cmd.Context()) if err != nil { return err } var data [][]string for _, m := range models.Models { if len(args) == 0 || strings.HasPrefix(m.Name, args[0]) { var procStr string switch { case m.SizeVRAM == 0: procStr = "100% CPU" case m.SizeVRAM == m.Size: procStr = "100% GPU" case m.SizeVRAM > m.Size || m.Size == 0: procStr = "Unknown" default: sizeCPU := m.Size - m.SizeVRAM cpuPercent := math.Round(float64(sizeCPU) / float64(m.Size) * 100) procStr = fmt.Sprintf("%d%%/%d%% CPU/GPU", int(cpuPercent), int(100-cpuPercent)) } data = append(data, []string{m.Name, m.Digest[:12], format.HumanBytes(m.Size), procStr, format.HumanTime(m.ExpiresAt, "Never")}) } } table := tablewriter.NewWriter(os.Stdout) table.SetHeader([]string{"NAME", "ID", "SIZE", "PROCESSOR", "UNTIL"}) table.SetHeaderAlignment(tablewriter.ALIGN_LEFT) table.SetAlignment(tablewriter.ALIGN_LEFT) table.SetHeaderLine(false) table.SetBorder(false) table.SetNoWhiteSpace(true) table.SetTablePadding("\t") table.AppendBulk(data) table.Render() return nil }
モデルの情報を問い合わせているのは、client.ListRunning(cmd.Context())のところです。
// ListRunning lists running models. func (c *Client) ListRunning(ctx context.Context) (*ProcessResponse, error) { var lr ProcessResponse if err := c.do(ctx, http.MethodGet, "/api/ps", nil, &lr); err != nil { return nil, err } return &lr, nil }
/api/psにGETリクエストを送り、レスポンスを受け取ります。デフォルトのサーバーでは、127.0.0.1:11434となっているので(OLLAMA_HOST環境変数で指定できる)、curlでGETしてみると、次のような内容が返ってきます。
{ "models": [ { "name": "llama3.1:latest", "model": "llama3.1:latest", "size": 6654289920, "digest": "91ab477bec9d27086a119e33c471ae7afbd786cc4fbd8f38d8af0a0b949d53aa", "details": { "parent_model": "", "format": "gguf", "family": "llama", "families": [ "llama" ], "parameter_size": "8.0B", "quantization_level": "Q4_0" }, "expires_at": "2024-09-07T21:28:58.954316925+09:00", "size_vram": 6654289920 } ] }
expires_atは例えば4 minutes from nowに変換され、size == size_vramの場合には100% GPUと表示される。また、IDはdigest[:12]が使われる。結果として、最初のような表示が行われることになる。
メモリサイズをどうやって計算しているかを知りたいと思ったが、そのためにはサーバー側の処理も読む必要がありそう。