Làm cách nào để gỡ lỗi chương trình MPI?


129

Tôi có một chương trình MPI biên dịch và chạy, nhưng tôi muốn bước qua nó để đảm bảo không có gì kỳ quái đang xảy ra. Lý tưởng nhất, tôi muốn một cách đơn giản để gắn GDB vào bất kỳ quy trình cụ thể nào, nhưng tôi không thực sự chắc chắn liệu điều đó có thể hay không. Một giải pháp thay thế sẽ là mỗi quá trình ghi đầu ra gỡ lỗi vào một tệp nhật ký riêng biệt, nhưng điều này không thực sự mang lại sự tự do như trình gỡ lỗi.

Có cách tiếp cận tốt hơn? Làm thế nào để bạn gỡ lỗi chương trình MPI?

Câu trả lời:


62

Như một người khác đã nói, TotalView là tiêu chuẩn cho việc này. Nhưng nó sẽ tốn của bạn một cánh tay và một chân.

Trang web OpenMPI có một Câu hỏi thường gặp tuyệt vời về gỡ lỗi MPI . Mục số 6 trong Câu hỏi thường gặp mô tả cách đính kèm các quy trình GDB vào MPI. Đọc toàn bộ, có một số lời khuyên tuyệt vời.

Tuy nhiên, nếu bạn thấy rằng bạn có quá nhiều quá trình để theo dõi, hãy kiểm tra Stack Trace Phân tích Công cụ (STAT) . Chúng tôi sử dụng điều này tại Livermore để thu thập các dấu vết ngăn xếp từ tiềm năng hàng trăm ngàn quy trình đang chạy và để thể hiện chúng một cách thông minh cho người dùng. Nó không phải là trình gỡ lỗi đầy đủ tính năng (trình gỡ lỗi đầy đủ tính năng sẽ không bao giờ mở rộng tới 208 nghìn lõi), nhưng nó sẽ cho bạn biết các nhóm quy trình nào đang làm điều tương tự. Sau đó, bạn có thể bước qua một đại diện từ mỗi nhóm trong trình gỡ lỗi tiêu chuẩn.


14
Tính đến năm 2010, Allinea DDT là một trình gỡ lỗi đầy đủ tính năng có quy mô lên tới hơn 208 nghìn lõi
Đánh dấu

1
Vì vậy, tôi sẽ tiếp tục và upvote câu trả lời của @ Mark ở đây. DDT là tốt đẹp. Hãy thử nó quá. TotalView cũng tích hợp với STAT ngay bây giờ, vì vậy nếu trang web của bạn có cài đặt TotalView, bạn cũng có thể thử điều đó. LLNL giữ TotalView và DDT, và thật tuyệt khi TotalView cuối cùng cũng có một số đối thủ cạnh tranh gay gắt.
Todd Gamblin

Tôi muốn thứ hai liên kết đến Câu hỏi thường gặp về gỡ lỗi MPI ( open-mpi.org/faq/?carget=debugging#serial-debuggers ). Cụ thể, đạn 6 là một cách tốt, nhanh chóng và dễ dàng (đủ cho cả tôi!) Để hiểu cách ít nhất là gỡ lỗi một quy trình riêng lẻ.
Jeff

Các bước trong # 6 của trang FAQ đã làm việc rất tốt cho tôi và giúp tôi tìm ra vấn đề của mình. Cảm ơn rất nhiều vì điều này.
Jon Deaton

86

Tôi đã tìm thấy gdb khá hữu ích. Tôi sử dụng nó như là

mpirun -np <NP> xterm -e gdb ./program 

Điều này khởi chạy các cửa sổ xterm mà tôi có thể làm

run <arg1> <arg2> ... <argN>

thường hoạt động tốt

Bạn cũng có thể gói các lệnh này với nhau bằng cách sử dụng:

mpirun -n <NP> xterm -hold -e gdb -ex run --args ./program [arg1] [arg2] [...]

Làm cách nào tôi có thể gửi cùng một đầu vào cho tất cả các NP gdb xterms? Ví dụ, tôi muốn thêm hai điểm dừng cho mỗi quy trình và có 16 quy trình. Có một số thay thế cho xterm để làm điều này? Chúng ta có thể kết nối các phiên thành một phiên bản duy nhất của màn hình, tmux hoặc Kẻ hủy diệt của Chris Jones không?
osgx

@osgx Bạn có thể làm điều này bằng cách lưu các lệnh ("break xxx", "break yyy", "run") vào <file>và chuyển -x <file>đến gdb.
eush77

nhưng tôi gặp lỗi, thông báo lỗi là "execvp error trên tệp xterm (Không có tệp hoặc thư mục như vậy)"
hitwlh

Khi tôi thử điều này với jdb & OpenMPI, nó không hoạt động, tức là mỗi phiên bản jdb nhìn thấy num_ranks bằng 1 thay vì những gì được đưa ra cho đối số -np. bất cứ ý tưởng tại sao?
Michel Müller

26

Nhiều bài viết ở đây là về GDB, nhưng không đề cập đến cách đính kèm vào một quy trình từ khi khởi động. Rõ ràng, bạn có thể đính kèm vào tất cả các quy trình:

mpiexec -n X gdb ./a.out

Nhưng điều đó cực kỳ không hiệu quả vì bạn sẽ phải quay lại để bắt đầu tất cả các quy trình của mình. Nếu bạn chỉ muốn gỡ lỗi một (hoặc một số lượng nhỏ) quy trình MPI, bạn có thể thêm nó dưới dạng thực thi riêng biệt trên dòng lệnh bằng cách sử dụng :toán tử:

mpiexec -n 1 gdb ./a.out : -n X-1 ./a.out

Bây giờ chỉ có một trong các quy trình của bạn sẽ nhận được GDB.


Tôi có thể sử dụng "mpiexec -n X gdb ./a.out", nhưng có cách nào để sử dụng chế độ gdb -tui không?
hitwlh

16

Như những người khác đã đề cập, nếu bạn chỉ làm việc với một số ít quy trình MPI, bạn có thể thử sử dụng nhiều phiên gdb , valgrind đáng chú ý hoặc cuộn giải pháp in / ghi nhật ký của riêng bạn.

Nếu bạn đang sử dụng nhiều quy trình hơn thế, bạn thực sự bắt đầu cần một trình gỡ lỗi thích hợp. Câu hỏi thường gặp về OpenMPI khuyến nghị cả Allinea DDTTotalView .

Tôi làm việc trên Allinea DDT . Đây là một trình gỡ lỗi mã nguồn đồ họa đầy đủ tính năng, vì vậy, bạn có thể:

  • Gỡ lỗi hoặc đính kèm vào (hơn 200k) quy trình MPI
  • Bước và tạm dừng chúng theo nhóm hoặc cá nhân
  • Thêm điểm dừng, đồng hồ và tracepoints
  • Bắt lỗi bộ nhớ và rò rỉ

...và như thế. Nếu bạn đã sử dụng Eclipse hoặc Visual Studio thì bạn sẽ ở nhà ngay.

Chúng tôi đã thêm một số tính năng thú vị đặc biệt để gỡ lỗi mã song song (có thể là MPI, đa luồng hoặc CUDA):

  • Biến vô hướng được tự động so sánh trên tất cả các quy trình: (nguồn: allinea.com )Biểu đồ thu nhỏ hiển thị giá trị qua các quy trình

  • Bạn cũng có thể theo dõi và lọc các giá trị của biến và biểu thức qua các quy trình và thời gian: Tracepoints ghi lại giá trị theo thời gian

Nó được sử dụng rộng rãi trong số 500 trang web HPC hàng đầu, như ORNL , NCSA , LLNL , Jülich et. al.

Giao diện khá linh hoạt; chúng tôi đã tính thời gian bước và hợp nhất các ngăn xếp và biến của 220.000 quy trình ở mức 0,1 như là một phần của thử nghiệm chấp nhận trên cụm Jaguar của Oak Ridge.

@tgamblin đã đề cập đến STAT xuất sắc , tích hợp với Allinea DDT , cũng như một số dự án nguồn mở phổ biến khác.



7

Nếu bạn là tmuxngười dùng, bạn sẽ cảm thấy rất thoải mái khi sử dụng tập lệnh của Benedikt Morbach :tmpi

Nguồn chính thức: https://github.com/moben/scripts/blob/master/tmpi

Ngã ba: https://github.com/Azrael3000/tmpi

Với nó, bạn có nhiều bảng (số lượng quy trình) được đồng bộ hóa (mọi lệnh được sao chép trên tất cả các bảng hoặc quy trình cùng một lúc để bạn tiết kiệm nhiều thời gian so với xterm -ecách tiếp cận). Ngoài ra, bạn có thể biết các giá trị của biến trong quy trình bạn muốn thực hiện printmà không phải chuyển sang bảng khác, điều này sẽ in trên mỗi bảng các giá trị của biến cho mỗi quy trình.

Nếu bạn không phải là tmuxngười dùng, tôi khuyên bạn nên dùng thử và xem.


2
Vì tmpi thực sự tuyệt vời và chính xác những gì tôi đang tìm kiếm, tôi đã chia nó trên tài khoản github của mình: github.com/Azrael3000/tmpi kể từ khi tác giả ban đầu gỡ bỏ nó
Azrael3000

6

http://github.com/jimktrains/pgdb/tree/master là một tiện ích tôi đã viết để thực hiện điều này. Có một số tài liệu và cảm thấy thoải mái để chiều tôi cho câu hỏi.

Về cơ bản, bạn gọi một chương trình perl bao bọc GDB và đưa kênh IO đến một máy chủ trung tâm. Điều này cho phép GDB chạy trên mỗi máy chủ và để bạn truy cập nó trên mỗi máy chủ tại thiết bị đầu cuối.


Cảm ơn! Tôi chắc chắn sẽ kiểm tra điều này vào lần tới khi tôi làm việc trong Bộ KH & ĐT.
Jay Conrod

5

Việc sử dụng screencùng với gdbđể gỡ lỗi các ứng dụng MPI hoạt động độc đáo, đặc biệt là nếu xtermkhông có sẵn hoặc bạn đang xử lý nhiều hơn một vài bộ xử lý. Có rất nhiều cạm bẫy trên đường đi với các tìm kiếm stackoverflow đi kèm, vì vậy tôi sẽ tái tạo đầy đủ giải pháp của mình.

Đầu tiên, thêm mã sau MPI_Init để in ra PID và tạm dừng chương trình để chờ bạn đính kèm. Các giải pháp tiêu chuẩn dường như là một vòng lặp vô hạn; Cuối cùng tôi đã giải quyết raise(SIGSTOP);, đòi hỏi một cuộc gọi thêm continueđể thoát trong gdb.

}
    int i, id, nid;
    MPI_Comm_rank(MPI_COMM_WORLD,&id);
    MPI_Comm_size(MPI_COMM_WORLD,&nid);
    for (i=0; i<nid; i++) {
        MPI_Barrier(MPI_COMM_WORLD);
        if (i==id) {
            fprintf(stderr,"PID %d rank %d\n",getpid(),id);
        }
        MPI_Barrier(MPI_COMM_WORLD);
    }
    raise(SIGSTOP);
}

Sau khi biên dịch, chạy chương trình thực thi trong nền và bắt stderr. Sau đó, bạn có thể grepgửi tệp stderr cho một số từ khóa (ở đây là chữ viết tắt) để có được PID và thứ hạng của mỗi quá trình.

MDRUN_EXE=../../Your/Path/To/bin/executable
MDRUN_ARG="-a arg1 -f file1 -e etc"

mpiexec -n 1 $MDRUN_EXE $MDRUN_ARG >> output 2>> error &

sleep 2

PIDFILE=pid.dat
grep PID error > $PIDFILE
PIDs=(`awk '{print $2}' $PIDFILE`)
RANKs=(`awk '{print $4}' $PIDFILE`)

Một phiên gdb có thể được đính kèm với mỗi quá trình với gdb $MDRUN_EXE $PID. Làm như vậy trong một phiên màn hình cho phép dễ dàng truy cập vào bất kỳ phiên gdb nào. -d -mkhởi động màn hình ở chế độ tách rời, -S "P$RANK"cho phép bạn đặt tên cho màn hình để dễ dàng truy cập sau và -ltùy chọn bash khởi động màn hình ở chế độ tương tác và giữ cho gdb không thoát ra ngay lập tức.

for i in `awk 'BEGIN {for (i=0;i<'${#PIDs[@]}';i++) {print i}}'`
do
    PID=${PIDs[$i]}
    RANK=${RANKs[$i]}
    screen -d -m -S "P$RANK" bash -l -c "gdb $MDRUN_EXE $PID"
done

Khi gdb đã bắt đầu trong màn hình, bạn có thể nhập kịch bản vào màn hình (để bạn không phải nhập mọi màn hình và nhập cùng một thứ) bằng cách sử dụng -X stufflệnh của màn hình . Một dòng mới được yêu cầu ở cuối lệnh. Ở đây các màn hình được truy cập bằng -S "P$i"cách sử dụng các tên được đưa ra trước đó. Các -p 0tùy chọn là rất quan trọng, nếu không lệnh liên tục thất bại (dựa trên hay không trước đó bạn đã gắn liền với màn hình).

for i in `awk 'BEGIN {for (i=0;i<'${#PIDs[@]}';i++) {print i}}'`
do
    screen -S "P$i" -p 0 -X stuff "set logging file debug.$i.log
"
    screen -S "P$i" -p 0 -X stuff "set logging overwrite on
"
    screen -S "P$i" -p 0 -X stuff "set logging on
"
    screen -S "P$i" -p 0 -X stuff "source debug.init
"
done

Tại thời điểm này, bạn có thể gắn vào bất kỳ màn hình nào bằng cách sử dụng screen -rS "P$i"và tháo ra bằng cách sử dụng Ctrl+A+D. Các lệnh có thể được gửi đến tất cả các phiên gdb tương tự với phần mã trước đó.


3

Ngoài ra còn có công cụ mã nguồn mở của tôi, padb, nhằm mục đích giúp lập trình song song. Tôi gọi nó là "Công cụ kiểm tra công việc" vì nó không chỉ hoạt động như một trình gỡ lỗi mà còn có thể hoạt động như một chương trình hàng đầu giống như song song. Chạy trong chế độ "Báo cáo đầy đủ", nó sẽ hiển thị cho bạn ngăn xếp dấu vết của mọi quy trình trong ứng dụng của bạn cùng với các biến cục bộ cho mọi chức năng trên mỗi cấp bậc (giả sử bạn đã biên dịch với -g). Nó cũng sẽ hiển thị cho bạn "hàng đợi tin nhắn MPI", đó là danh sách gửi và nhận nổi bật cho mỗi cấp bậc trong công việc.

Ngoài việc hiển thị báo cáo đầy đủ, bạn cũng có thể yêu cầu padb phóng to từng bit thông tin trong công việc, có vô số tùy chọn và mục cấu hình để kiểm soát thông tin nào được hiển thị, xem trang web để biết thêm chi tiết.

Padb


3

Cách "chuẩn" để gỡ lỗi các chương trình MPI là sử dụng trình gỡ lỗi hỗ trợ mô hình thực thi đó.

Trên UNIX, TotalView được cho là có khả năng hỗ trợ tốt cho MPI.


2

Tôi sử dụng phương thức homebrewn nhỏ này để đính kèm trình gỡ lỗi vào các quy trình MPI - gọi hàm sau, DebugWait (), ngay sau MPI_Init () trong mã của bạn. Bây giờ trong khi các quy trình đang chờ nhập bàn phím, bạn có toàn bộ thời gian để đính kèm trình gỡ lỗi cho chúng và thêm các điểm dừng. Khi bạn đã hoàn tất, cung cấp một đầu vào ký tự và bạn đã sẵn sàng để đi.

static void DebugWait(int rank) {
    char    a;

    if(rank == 0) {
        scanf("%c", &a);
        printf("%d: Starting now\n", rank);
    } 

    MPI_Bcast(&a, 1, MPI_BYTE, 0, MPI_COMM_WORLD);
    printf("%d: Starting now\n", rank);
}

Tất nhiên bạn chỉ muốn biên dịch hàm này cho các bản dựng gỡ lỗi.


Bộ KH & ĐT đã yêu cầu các câu lệnh gỡ lỗi nhiều nhất tôi từng viết cho mã đơn giản. (lol) Điều này có thể rất hữu ích.
Troggy

3
Giải pháp này tương tự như viên đạn 6 ở đây ( open-mpi.org/faq/?carget=debugging#serial-debuggers ). Bạn có thể cải thiện mã của bạn một chút bằng cách thêm gethostname(hostname, sizeof(hostname)); printf("PID %d on host %s ready for attach\n", getpid(), hostname);. Sau đó, bạn đính kèm vào quá trình bằng cách gõ rsh <hostname_from_print_statement>, và cuối cùng gdb --pid=<PID_from_print_statement>.
Jeff

2

Lệnh để gắn gdb vào một quá trình mpi là không đầy đủ, nó phải là

mpirun -np <NP> xterm -e gdb ./program 

Một cuộc thảo luận ngắn gọn về mpi và gdb có thể được tìm thấy ở đây


2

Một cách đơn giản để gỡ lỗi chương trình MPI.

Trong hàm main () thêm chế độ ngủ (some_seconds)

Chạy chương trình như bình thường

$ mpirun -np <num_of_proc> <prog> <prog_args>

Chương trình sẽ bắt đầu và đi vào giấc ngủ.

Vì vậy, bạn sẽ có một vài giây để tìm cho bạn các quy trình bằng ps, chạy gdb và đính kèm với chúng.

Nếu bạn sử dụng một số trình soạn thảo như QtCreator, bạn có thể sử dụng

Gỡ lỗi-> Bắt đầu gỡ lỗi-> Đính kèm vào ứng dụng đang chạy

và tìm bạn xử lý ở đó.


1

Tôi thực hiện một số gỡ lỗi liên quan đến MPI với dấu vết nhật ký, nhưng bạn cũng có thể chạy gdb nếu bạn đang sử dụng mpich2: MPICH2 và gdb . Kỹ thuật này nói chung là một cách thực hành tốt khi bạn đang xử lý một quy trình khó để khởi chạy từ trình gỡ lỗi.


Thay đổi thành một liên kết khác không bị hỏng, thêm một số bình luận.
Jim Hunziker


0

Một giải pháp khác là chạy mã của bạn trong SMPI, MPI mô phỏng. Đó là một dự án nguồn mở mà tôi tham gia. Mỗi xếp hạng MPI sẽ được chuyển đổi thành các luồng của cùng một quy trình UNIX. Sau đó, bạn có thể dễ dàng sử dụng gdb để xếp hạng MPI.

SMPI đề xuất những lợi thế khác cho việc nghiên cứu các ứng dụng MPI: clairevoyance (bạn có thể quan sát mọi bộ phận của hệ thống), khả năng tái tạo (một số lần chạy dẫn đến cùng một hành vi trừ khi bạn chỉ định như vậy), sự vắng mặt của heisenbugs (vì nền tảng mô phỏng được giữ khác nhau từ máy chủ lưu trữ), v.v.

Để biết thêm thông tin, xem bài trình bày này , hoặc câu trả lời liên quan .

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.